├── Loader_Files ├── H7 device │ ├── Dev_Inf.c │ ├── Dev_Inf.h │ ├── Loader_Src.c │ └── linker.ld ├── command.txt └── other devices │ ├── Dev_Inf.c │ ├── Dev_Inf.h │ ├── Loader_Src.c │ └── linker.ld ├── QSPI Drivers ├── GD25Q80C │ ├── quadspi.c │ └── quadspi.h ├── IS25LP128F │ ├── quadspi.c │ └── quadspi.h ├── MT25QL512 │ ├── quadspi.c │ └── quadspi.h ├── MX25L51245G │ ├── quadspi.c │ └── quadspi.h └── N25Q256A │ ├── quadspi.c │ └── quadspi.h ├── QSPI testing ├── main_test.c └── testbinary1M.bin └── README.md /Loader_Files/H7 device/Dev_Inf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Dev_Inf.c 3 | * 4 | */ 5 | #include "Dev_Inf.h" 6 | #include "quadspi.h" 7 | 8 | /* This structure contains information used by ST-LINK Utility to program and erase the device */ 9 | #if defined (__ICCARM__) 10 | __root struct StorageInfo const StorageInfo = { 11 | #else 12 | struct StorageInfo const StorageInfo = { 13 | #endif 14 | "QSPI_flashloader_CSP", // Device Name + version number 15 | NOR_FLASH, // Device Type 16 | 0x90000000, // Device Start Address 17 | MEMORY_FLASH_SIZE, // Device Size in Bytes 18 | MEMORY_PAGE_SIZE, // Programming Page Size 19 | 0xFF, // Initial Content of Erased Memory 20 | 21 | // Specify Size and Address of Sectors (view example below) 22 | { { (MEMORY_FLASH_SIZE / MEMORY_SECTOR_SIZE), // Sector Numbers, 23 | (uint32_t) MEMORY_SECTOR_SIZE }, //Sector Size 24 | 25 | { 0x00000000, 0x00000000 } } }; -------------------------------------------------------------------------------- /Loader_Files/H7 device/Dev_Inf.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef DEV_INF_H_ 3 | #define DEV_INF_H_ 4 | 5 | #define MCU_FLASH 1 6 | #define NAND_FLASH 2 7 | #define NOR_FLASH 3 8 | #define SRAM 4 9 | #define PSRAM 5 10 | #define PC_CARD 6 11 | #define SPI_FLASH 7 12 | #define I2C_FLASH 8 13 | #define SDRAM 9 14 | #define I2C_EEPROM 10 15 | 16 | #define SECTOR_NUM 10 // Max Number of Sector types 17 | 18 | struct DeviceSectors 19 | { 20 | unsigned long SectorNum; // Number of Sectors 21 | unsigned long SectorSize; // Sector Size in Bytes 22 | }; 23 | 24 | struct StorageInfo 25 | { 26 | char DeviceName[100]; // Device Name and Description 27 | unsigned short DeviceType; // Device Type: ONCHIP, EXT8BIT, EXT16BIT, ... 28 | unsigned long DeviceStartAddress; // Default Device Start Address 29 | unsigned long DeviceSize; // Total Size of Device 30 | unsigned long PageSize; // Programming Page Size 31 | unsigned char EraseValue; // Content of Erased Memory 32 | struct DeviceSectors sectors[SECTOR_NUM]; 33 | }; 34 | 35 | 36 | 37 | #endif /* DEV_INF_H_ */ 38 | -------------------------------------------------------------------------------- /Loader_Files/H7 device/Loader_Src.c: -------------------------------------------------------------------------------- 1 | #include "quadspi.h" 2 | #include "main.h" 3 | #include "gpio.h" 4 | 5 | #define LOADER_OK 0x1 6 | #define LOADER_FAIL 0x0 7 | 8 | extern void SystemClock_Config(void); 9 | 10 | /** 11 | * @brief System initialization. 12 | * @param None 13 | * @retval LOADER_OK = 1 : Operation succeeded 14 | * @retval LOADER_FAIL = 0 : Operation failed 15 | */ 16 | int Init(void) { 17 | 18 | *(uint32_t*)0xE000EDF0=0xA05F0000; //enable interrupts in debug 19 | 20 | 21 | SystemInit(); 22 | 23 | /* ADAPTATION TO THE DEVICE 24 | * 25 | * change VTOR setting for H7 device 26 | * SCB->VTOR = 0x24000000 | 0x200; 27 | * 28 | * change VTOR setting for other devices 29 | * SCB->VTOR = 0x20000000 | 0x200; 30 | * 31 | * */ 32 | 33 | SCB->VTOR = 0x24000000 | 0x200; 34 | 35 | __set_PRIMASK(0); //enable interrupts 36 | 37 | HAL_Init(); 38 | 39 | SystemClock_Config(); 40 | 41 | MX_GPIO_Init(); 42 | 43 | __HAL_RCC_QSPI_FORCE_RESET(); //completely reset peripheral 44 | __HAL_RCC_QSPI_RELEASE_RESET(); 45 | 46 | if (CSP_QUADSPI_Init() != HAL_OK) 47 | { 48 | __set_PRIMASK(1); //disable interrupts 49 | return LOADER_FAIL; 50 | } 51 | 52 | 53 | if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK) 54 | { 55 | __set_PRIMASK(1); //disable interrupts 56 | return LOADER_FAIL; 57 | } 58 | 59 | /*Trigger read access before HAL_QSPI_Abort() otherwise abort functionality gets stuck*/ 60 | uint32_t a = *(uint32_t*) 0x90000000; 61 | a++; 62 | 63 | __set_PRIMASK(1); //disable interrupts 64 | return LOADER_OK; 65 | } 66 | 67 | /** 68 | * @brief Program memory. 69 | * @param Address: page address 70 | * @param Size : size of data 71 | * @param buffer : pointer to data buffer 72 | * @retval LOADER_OK = 1 : Operation succeeded 73 | * @retval LOADER_FAIL = 0 : Operation failed 74 | */ 75 | int Write(uint32_t Address, uint32_t Size, uint8_t* buffer) { 76 | 77 | __set_PRIMASK(0); //enable interrupts 78 | 79 | if(HAL_QSPI_Abort(&hqspi) != HAL_OK) 80 | { 81 | __set_PRIMASK(1); //disable interrupts 82 | return LOADER_FAIL; 83 | } 84 | 85 | 86 | if (CSP_QSPI_WriteMemory((uint8_t*) buffer, (Address & (0x0fffffff)),Size) != HAL_OK) 87 | { 88 | __set_PRIMASK(1); //disable interrupts 89 | return LOADER_FAIL; 90 | } 91 | 92 | __set_PRIMASK(1); //disable interrupts 93 | return LOADER_OK; 94 | } 95 | 96 | /** 97 | * @brief Sector erase. 98 | * @param EraseStartAddress : erase start address 99 | * @param EraseEndAddress : erase end address 100 | * @retval LOADER_OK = 1 : Operation succeeded 101 | * @retval LOADER_FAIL = 0 : Operation failed 102 | */ 103 | int SectorErase(uint32_t EraseStartAddress, uint32_t EraseEndAddress) { 104 | 105 | __set_PRIMASK(0); //enable interrupts 106 | 107 | if(HAL_QSPI_Abort(&hqspi) != HAL_OK) 108 | { 109 | __set_PRIMASK(1); //disable interrupts 110 | return LOADER_FAIL; 111 | } 112 | 113 | 114 | if (CSP_QSPI_EraseSector(EraseStartAddress, EraseEndAddress) != HAL_OK) 115 | { 116 | __set_PRIMASK(1); //disable interrupts 117 | return LOADER_FAIL; 118 | } 119 | 120 | __set_PRIMASK(1); //disable interrupts 121 | return LOADER_OK; 122 | } 123 | 124 | /** 125 | * Description : 126 | * Mass erase of external flash area 127 | * Optional command - delete in case usage of mass erase is not planed 128 | * Inputs : 129 | * none 130 | * outputs : 131 | * none 132 | * Note: Optional for all types of device 133 | */ 134 | int MassErase(void) { 135 | 136 | __set_PRIMASK(0); //enable interrupts 137 | 138 | if(HAL_QSPI_Abort(&hqspi) != HAL_OK) 139 | { 140 | __set_PRIMASK(1); //disable interrupts 141 | return LOADER_FAIL; 142 | } 143 | 144 | 145 | if (CSP_QSPI_Erase_Chip() != HAL_OK) 146 | { 147 | __set_PRIMASK(1); //disable interrupts 148 | return LOADER_FAIL; 149 | } 150 | 151 | __set_PRIMASK(1); //disable interrupts 152 | return LOADER_OK; 153 | } 154 | 155 | /** 156 | * Description : 157 | * Calculates checksum value of the memory zone 158 | * Inputs : 159 | * StartAddress : Flash start address 160 | * Size : Size (in WORD) 161 | * InitVal : Initial CRC value 162 | * outputs : 163 | * R0 : Checksum value 164 | * Note: Optional for all types of device 165 | */ 166 | uint32_t CheckSum(uint32_t StartAddress, uint32_t Size, uint32_t InitVal) { 167 | uint8_t missalignementAddress = StartAddress % 4; 168 | uint8_t missalignementSize = Size; 169 | int cnt; 170 | uint32_t Val; 171 | 172 | StartAddress -= StartAddress % 4; 173 | Size += (Size % 4 == 0) ? 0 : 4 - (Size % 4); 174 | 175 | for (cnt = 0; cnt < Size; cnt += 4) { 176 | Val = *(uint32_t*) StartAddress; 177 | if (missalignementAddress) { 178 | switch (missalignementAddress) { 179 | case 1: 180 | InitVal += (uint8_t) (Val >> 8 & 0xff); 181 | InitVal += (uint8_t) (Val >> 16 & 0xff); 182 | InitVal += (uint8_t) (Val >> 24 & 0xff); 183 | missalignementAddress -= 1; 184 | break; 185 | case 2: 186 | InitVal += (uint8_t) (Val >> 16 & 0xff); 187 | InitVal += (uint8_t) (Val >> 24 & 0xff); 188 | missalignementAddress -= 2; 189 | break; 190 | case 3: 191 | InitVal += (uint8_t) (Val >> 24 & 0xff); 192 | missalignementAddress -= 3; 193 | break; 194 | } 195 | } else if ((Size - missalignementSize) % 4 && (Size - cnt) <= 4) { 196 | switch (Size - missalignementSize) { 197 | case 1: 198 | InitVal += (uint8_t) Val; 199 | InitVal += (uint8_t) (Val >> 8 & 0xff); 200 | InitVal += (uint8_t) (Val >> 16 & 0xff); 201 | missalignementSize -= 1; 202 | break; 203 | case 2: 204 | InitVal += (uint8_t) Val; 205 | InitVal += (uint8_t) (Val >> 8 & 0xff); 206 | missalignementSize -= 2; 207 | break; 208 | case 3: 209 | InitVal += (uint8_t) Val; 210 | missalignementSize -= 3; 211 | break; 212 | } 213 | } else { 214 | InitVal += (uint8_t) Val; 215 | InitVal += (uint8_t) (Val >> 8 & 0xff); 216 | InitVal += (uint8_t) (Val >> 16 & 0xff); 217 | InitVal += (uint8_t) (Val >> 24 & 0xff); 218 | } 219 | StartAddress += 4; 220 | } 221 | 222 | return (InitVal); 223 | } 224 | 225 | /** 226 | * Description : 227 | * Verify flash memory with RAM buffer and calculates checksum value of 228 | * the programmed memory 229 | * Inputs : 230 | * FlashAddr : Flash address 231 | * RAMBufferAddr : RAM buffer address 232 | * Size : Size (in WORD) 233 | * InitVal : Initial CRC value 234 | * outputs : 235 | * R0 : Operation failed (address of failure) 236 | * R1 : Checksum value 237 | * Note: Optional for all types of device 238 | */ 239 | uint64_t Verify(uint32_t MemoryAddr, uint32_t RAMBufferAddr, uint32_t Size,uint32_t missalignement){ 240 | 241 | __set_PRIMASK(0); //enable interrupts 242 | uint32_t VerifiedData = 0, InitVal = 0; 243 | uint64_t checksum; 244 | Size *= 4; 245 | 246 | if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK) 247 | { 248 | __set_PRIMASK(1); //disable interrupts 249 | return LOADER_FAIL; 250 | } 251 | 252 | checksum = CheckSum((uint32_t) MemoryAddr + (missalignement & 0xf), 253 | Size - ((missalignement >> 16) & 0xF), InitVal); 254 | while (Size > VerifiedData) { 255 | if (*(uint8_t*) MemoryAddr++ 256 | != *((uint8_t*) RAMBufferAddr + VerifiedData)){ 257 | __set_PRIMASK(1); //disable interrupts 258 | return ((checksum << 32) + (MemoryAddr + VerifiedData)); 259 | } 260 | VerifiedData++; 261 | } 262 | 263 | __set_PRIMASK(1); //disable interrupts 264 | return (checksum << 32); 265 | } 266 | -------------------------------------------------------------------------------- /Loader_Files/H7 device/linker.ld: -------------------------------------------------------------------------------- 1 | /* 2 | ***************************************************************************** 3 | ** File : linker.ld 4 | ** 5 | ** Set heap size, stack size and stack location according 6 | ** to application requirements. 7 | ** 8 | ** Set memory bank area and size if external memory is used. 9 | ** 10 | ** Target : STMicroelectronics STM32 11 | ** 12 | ***************************************************************************** 13 | */ 14 | 15 | /* Entry Point */ 16 | ENTRY(Init) 17 | 18 | /* Generate 2 segment for Loader code and device info */ 19 | PHDRS {Loader PT_LOAD ; SgInfo PT_LOAD ; } 20 | 21 | /* Highest address of the user mode stack */ 22 | _estack = ORIGIN(RAM_D1) + LENGTH(RAM_D1); /* end of RAM */ 23 | /* Generate a link error if heap and stack don't fit into RAM */ 24 | _Min_Heap_Size = 0x200; /* required amount of heap */ 25 | _Min_Stack_Size = 0x400; /* required amount of stack */ 26 | 27 | /* Specify the memory areas */ 28 | MEMORY 29 | { 30 | RAM_D1 (xrw) : ORIGIN = 0x24000004, LENGTH = 512K 31 | } 32 | 33 | /* Define output sections */ 34 | SECTIONS 35 | { 36 | /* The startup code goes first into FLASH */ 37 | .isr_vector : 38 | { 39 | . = . + 0x1FC; 40 | . = ALIGN(4); 41 | KEEP(*(.isr_vector)) /* Startup code */ 42 | . = ALIGN(4); 43 | } >RAM_D1 :Loader 44 | 45 | .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >RAM_D1 46 | .ARM : { 47 | __exidx_start = .; 48 | *(.ARM.exidx*) 49 | __exidx_end = .; 50 | } >RAM_D1 :Loader 51 | 52 | .preinit_array : 53 | { 54 | PROVIDE_HIDDEN (__preinit_array_start = .); 55 | KEEP (*(.preinit_array*)) 56 | PROVIDE_HIDDEN (__preinit_array_end = .); 57 | } >RAM_D1 :Loader 58 | 59 | .init_array : 60 | { 61 | PROVIDE_HIDDEN (__init_array_start = .); 62 | KEEP (*(SORT(.init_array.*))) 63 | KEEP (*(.init_array*)) 64 | PROVIDE_HIDDEN (__init_array_end = .); 65 | } >RAM_D1 :Loader 66 | 67 | .fini_array : 68 | { 69 | PROVIDE_HIDDEN (__fini_array_start = .); 70 | KEEP (*(SORT(.fini_array.*))) 71 | KEEP (*(.fini_array*)) 72 | PROVIDE_HIDDEN (__fini_array_end = .); 73 | } >RAM_D1 :Loader 74 | 75 | /* used by the startup to initialize data */ 76 | _sidata = LOADADDR(.data); 77 | 78 | /* Initialized data sections goes into RAM, load LMA copy after code */ 79 | .data : 80 | { 81 | . = ALIGN(4); 82 | _sdata = .; /* create a global symbol at data start */ 83 | *(.data) /* .data sections */ 84 | *(.data*) /* .data* sections */ 85 | 86 | . = ALIGN(4); 87 | _edata = .; /* define a global symbol at data end */ 88 | } >RAM_D1 :Loader 89 | 90 | 91 | /* Uninitialized data section */ 92 | . = ALIGN(4); 93 | .bss : 94 | { 95 | /* This is used by the startup in order to initialize the .bss secion */ 96 | _sbss = .; /* define a global symbol at bss start */ 97 | __bss_start__ = _sbss; 98 | *(.bss) 99 | *(.bss*) 100 | *(COMMON) 101 | 102 | . = ALIGN(4); 103 | _ebss = .; /* define a global symbol at bss end */ 104 | __bss_end__ = _ebss; 105 | } >RAM_D1 :Loader 106 | 107 | /* The program code and other data goes into FLASH */ 108 | .text : 109 | { 110 | . = ALIGN(4); 111 | *(.text) /* .text sections (code) */ 112 | *(.text*) /* .text* sections (code) */ 113 | *(.glue_7) /* glue arm to thumb code */ 114 | *(.glue_7t) /* glue thumb to arm code */ 115 | *(.eh_frame) 116 | 117 | KEEP (*(.init)) 118 | KEEP (*(.fini)) 119 | 120 | . = ALIGN(4); 121 | _etext = .; /* define a global symbols at end of code */ 122 | } >RAM_D1 :Loader 123 | 124 | .Dev_info : 125 | { 126 | KEEP(*Dev_Inf.o ( .rodata* )) 127 | } :SgInfo 128 | 129 | 130 | /* Constant data goes into FLASH */ 131 | .rodata : 132 | { 133 | . = ALIGN(4); 134 | *(.rodata) /* .rodata sections (constants, strings, etc.) */ 135 | *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ 136 | . = ALIGN(4); 137 | } >RAM_D1 :Loader 138 | 139 | 140 | /* User_heap_stack section, used to check that there is enough RAM left */ 141 | ._user_heap_stack : 142 | { 143 | . = ALIGN(4); 144 | PROVIDE ( end = . ); 145 | PROVIDE ( _end = . ); 146 | . = . + _Min_Heap_Size; 147 | . = . + _Min_Stack_Size; 148 | . = ALIGN(4); 149 | } >RAM_D1 :Loader 150 | 151 | .ARM.attributes 0 : { *(.ARM.attributes) } 152 | } 153 | 154 | 155 | -------------------------------------------------------------------------------- /Loader_Files/command.txt: -------------------------------------------------------------------------------- 1 | cmd.exe /C copy/Y "${BuildArtifactFileBaseName}.elf" "..\QSPI_flashloader_CSP.stldr" -------------------------------------------------------------------------------- /Loader_Files/other devices/Dev_Inf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Dev_Inf.c 3 | * 4 | */ 5 | #include "Dev_Inf.h" 6 | #include "quadspi.h" 7 | 8 | /* This structure contains information used by ST-LINK Utility to program and erase the device */ 9 | #if defined (__ICCARM__) 10 | __root struct StorageInfo const StorageInfo = { 11 | #else 12 | struct StorageInfo const StorageInfo = { 13 | #endif 14 | "QSPI_flashloader_CSP", // Device Name + version number 15 | NOR_FLASH, // Device Type 16 | 0x90000000, // Device Start Address 17 | MEMORY_FLASH_SIZE, // Device Size in Bytes 18 | MEMORY_PAGE_SIZE, // Programming Page Size 19 | 0xFF, // Initial Content of Erased Memory 20 | 21 | // Specify Size and Address of Sectors (view example below) 22 | { { (MEMORY_FLASH_SIZE / MEMORY_SECTOR_SIZE), // Sector Numbers, 23 | (uint32_t) MEMORY_SECTOR_SIZE }, //Sector Size 24 | 25 | { 0x00000000, 0x00000000 } } }; -------------------------------------------------------------------------------- /Loader_Files/other devices/Dev_Inf.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef DEV_INF_H_ 3 | #define DEV_INF_H_ 4 | 5 | #define MCU_FLASH 1 6 | #define NAND_FLASH 2 7 | #define NOR_FLASH 3 8 | #define SRAM 4 9 | #define PSRAM 5 10 | #define PC_CARD 6 11 | #define SPI_FLASH 7 12 | #define I2C_FLASH 8 13 | #define SDRAM 9 14 | #define I2C_EEPROM 10 15 | 16 | #define SECTOR_NUM 10 // Max Number of Sector types 17 | 18 | struct DeviceSectors 19 | { 20 | unsigned long SectorNum; // Number of Sectors 21 | unsigned long SectorSize; // Sector Size in Bytes 22 | }; 23 | 24 | struct StorageInfo 25 | { 26 | char DeviceName[100]; // Device Name and Description 27 | unsigned short DeviceType; // Device Type: ONCHIP, EXT8BIT, EXT16BIT, ... 28 | unsigned long DeviceStartAddress; // Default Device Start Address 29 | unsigned long DeviceSize; // Total Size of Device 30 | unsigned long PageSize; // Programming Page Size 31 | unsigned char EraseValue; // Content of Erased Memory 32 | struct DeviceSectors sectors[SECTOR_NUM]; 33 | }; 34 | 35 | 36 | 37 | #endif /* DEV_INF_H_ */ 38 | -------------------------------------------------------------------------------- /Loader_Files/other devices/Loader_Src.c: -------------------------------------------------------------------------------- 1 | #include "quadspi.h" 2 | #include "main.h" 3 | #include "gpio.h" 4 | 5 | #define LOADER_OK 0x1 6 | #define LOADER_FAIL 0x0 7 | 8 | extern void SystemClock_Config(void); 9 | 10 | /** 11 | * @brief System initialization. 12 | * @param None 13 | * @retval LOADER_OK = 1 : Operation succeeded 14 | * @retval LOADER_FAIL = 0 : Operation failed 15 | */ 16 | int Init(void) { 17 | 18 | *(uint32_t*)0xE000EDF0=0xA05F0000; //enable interrupts in debug 19 | 20 | 21 | SystemInit(); 22 | 23 | /* ADAPTATION TO THE DEVICE 24 | * 25 | * change VTOR setting for H7 device 26 | * SCB->VTOR = 0x24000000 | 0x200; 27 | * 28 | * change VTOR setting for other devices 29 | * SCB->VTOR = 0x20000000 | 0x200; 30 | * 31 | * */ 32 | 33 | SCB->VTOR = 0x20000000 | 0x200; 34 | 35 | __set_PRIMASK(0); //enable interrupts 36 | 37 | HAL_Init(); 38 | 39 | SystemClock_Config(); 40 | 41 | MX_GPIO_Init(); 42 | 43 | __HAL_RCC_QSPI_FORCE_RESET(); //completely reset peripheral 44 | __HAL_RCC_QSPI_RELEASE_RESET(); 45 | 46 | if (CSP_QUADSPI_Init() != HAL_OK) 47 | { 48 | __set_PRIMASK(1); //disable interrupts 49 | return LOADER_FAIL; 50 | } 51 | 52 | 53 | if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK) 54 | { 55 | __set_PRIMASK(1); //disable interrupts 56 | return LOADER_FAIL; 57 | } 58 | 59 | 60 | __set_PRIMASK(1); //disable interrupts 61 | return LOADER_OK; 62 | } 63 | 64 | /** 65 | * @brief Program memory. 66 | * @param Address: page address 67 | * @param Size : size of data 68 | * @param buffer : pointer to data buffer 69 | * @retval LOADER_OK = 1 : Operation succeeded 70 | * @retval LOADER_FAIL = 0 : Operation failed 71 | */ 72 | int Write(uint32_t Address, uint32_t Size, uint8_t* buffer) { 73 | 74 | __set_PRIMASK(0); //enable interrupts 75 | 76 | if(HAL_QSPI_Abort(&hqspi) != HAL_OK) 77 | { 78 | __set_PRIMASK(1); //disable interrupts 79 | return LOADER_FAIL; 80 | } 81 | 82 | 83 | if (CSP_QSPI_WriteMemory((uint8_t*) buffer, (Address & (0x0fffffff)),Size) != HAL_OK) 84 | { 85 | __set_PRIMASK(1); //disable interrupts 86 | return LOADER_FAIL; 87 | } 88 | 89 | __set_PRIMASK(1); //disable interrupts 90 | return LOADER_OK; 91 | } 92 | 93 | /** 94 | * @brief Sector erase. 95 | * @param EraseStartAddress : erase start address 96 | * @param EraseEndAddress : erase end address 97 | * @retval LOADER_OK = 1 : Operation succeeded 98 | * @retval LOADER_FAIL = 0 : Operation failed 99 | */ 100 | int SectorErase(uint32_t EraseStartAddress, uint32_t EraseEndAddress) { 101 | 102 | __set_PRIMASK(0); //enable interrupts 103 | 104 | if(HAL_QSPI_Abort(&hqspi) != HAL_OK) 105 | { 106 | __set_PRIMASK(1); //disable interrupts 107 | return LOADER_FAIL; 108 | } 109 | 110 | 111 | if (CSP_QSPI_EraseSector(EraseStartAddress, EraseEndAddress) != HAL_OK) 112 | { 113 | __set_PRIMASK(1); //disable interrupts 114 | return LOADER_FAIL; 115 | } 116 | 117 | __set_PRIMASK(1); //disable interrupts 118 | return LOADER_OK; 119 | } 120 | 121 | /** 122 | * Description : 123 | * Mass erase of external flash area 124 | * Optional command - delete in case usage of mass erase is not planed 125 | * Inputs : 126 | * none 127 | * outputs : 128 | * none 129 | * Note: Optional for all types of device 130 | */ 131 | int MassErase(void) { 132 | 133 | __set_PRIMASK(0); //enable interrupts 134 | 135 | if(HAL_QSPI_Abort(&hqspi) != HAL_OK) 136 | { 137 | __set_PRIMASK(1); //disable interrupts 138 | return LOADER_FAIL; 139 | } 140 | 141 | 142 | if (CSP_QSPI_Erase_Chip() != HAL_OK) 143 | { 144 | __set_PRIMASK(1); //disable interrupts 145 | return LOADER_FAIL; 146 | } 147 | 148 | __set_PRIMASK(1); //disable interrupts 149 | return LOADER_OK; 150 | } 151 | 152 | /** 153 | * Description : 154 | * Calculates checksum value of the memory zone 155 | * Inputs : 156 | * StartAddress : Flash start address 157 | * Size : Size (in WORD) 158 | * InitVal : Initial CRC value 159 | * outputs : 160 | * R0 : Checksum value 161 | * Note: Optional for all types of device 162 | */ 163 | uint32_t CheckSum(uint32_t StartAddress, uint32_t Size, uint32_t InitVal) { 164 | uint8_t missalignementAddress = StartAddress % 4; 165 | uint8_t missalignementSize = Size; 166 | int cnt; 167 | uint32_t Val; 168 | 169 | StartAddress -= StartAddress % 4; 170 | Size += (Size % 4 == 0) ? 0 : 4 - (Size % 4); 171 | 172 | for (cnt = 0; cnt < Size; cnt += 4) { 173 | Val = *(uint32_t*) StartAddress; 174 | if (missalignementAddress) { 175 | switch (missalignementAddress) { 176 | case 1: 177 | InitVal += (uint8_t) (Val >> 8 & 0xff); 178 | InitVal += (uint8_t) (Val >> 16 & 0xff); 179 | InitVal += (uint8_t) (Val >> 24 & 0xff); 180 | missalignementAddress -= 1; 181 | break; 182 | case 2: 183 | InitVal += (uint8_t) (Val >> 16 & 0xff); 184 | InitVal += (uint8_t) (Val >> 24 & 0xff); 185 | missalignementAddress -= 2; 186 | break; 187 | case 3: 188 | InitVal += (uint8_t) (Val >> 24 & 0xff); 189 | missalignementAddress -= 3; 190 | break; 191 | } 192 | } else if ((Size - missalignementSize) % 4 && (Size - cnt) <= 4) { 193 | switch (Size - missalignementSize) { 194 | case 1: 195 | InitVal += (uint8_t) Val; 196 | InitVal += (uint8_t) (Val >> 8 & 0xff); 197 | InitVal += (uint8_t) (Val >> 16 & 0xff); 198 | missalignementSize -= 1; 199 | break; 200 | case 2: 201 | InitVal += (uint8_t) Val; 202 | InitVal += (uint8_t) (Val >> 8 & 0xff); 203 | missalignementSize -= 2; 204 | break; 205 | case 3: 206 | InitVal += (uint8_t) Val; 207 | missalignementSize -= 3; 208 | break; 209 | } 210 | } else { 211 | InitVal += (uint8_t) Val; 212 | InitVal += (uint8_t) (Val >> 8 & 0xff); 213 | InitVal += (uint8_t) (Val >> 16 & 0xff); 214 | InitVal += (uint8_t) (Val >> 24 & 0xff); 215 | } 216 | StartAddress += 4; 217 | } 218 | 219 | return (InitVal); 220 | } 221 | 222 | /** 223 | * Description : 224 | * Verify flash memory with RAM buffer and calculates checksum value of 225 | * the programmed memory 226 | * Inputs : 227 | * FlashAddr : Flash address 228 | * RAMBufferAddr : RAM buffer address 229 | * Size : Size (in WORD) 230 | * InitVal : Initial CRC value 231 | * outputs : 232 | * R0 : Operation failed (address of failure) 233 | * R1 : Checksum value 234 | * Note: Optional for all types of device 235 | */ 236 | uint64_t Verify(uint32_t MemoryAddr, uint32_t RAMBufferAddr, uint32_t Size,uint32_t missalignement){ 237 | 238 | __set_PRIMASK(0); //enable interrupts 239 | uint32_t VerifiedData = 0, InitVal = 0; 240 | uint64_t checksum; 241 | Size *= 4; 242 | 243 | if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK) 244 | { 245 | __set_PRIMASK(1); //disable interrupts 246 | return LOADER_FAIL; 247 | } 248 | 249 | checksum = CheckSum((uint32_t) MemoryAddr + (missalignement & 0xf), 250 | Size - ((missalignement >> 16) & 0xF), InitVal); 251 | while (Size > VerifiedData) { 252 | if (*(uint8_t*) MemoryAddr++ 253 | != *((uint8_t*) RAMBufferAddr + VerifiedData)){ 254 | __set_PRIMASK(1); //disable interrupts 255 | return ((checksum << 32) + (MemoryAddr + VerifiedData)); 256 | } 257 | VerifiedData++; 258 | } 259 | 260 | __set_PRIMASK(1); //disable interrupts 261 | return (checksum << 32); 262 | } 263 | -------------------------------------------------------------------------------- /Loader_Files/other devices/linker.ld: -------------------------------------------------------------------------------- 1 | /* 2 | ***************************************************************************** 3 | ** File : linker.ld 4 | ** 5 | ** Set heap size, stack size and stack location according 6 | ** to application requirements. 7 | ** 8 | ** Set memory bank area and size if external memory is used. 9 | ** 10 | ** Target : STMicroelectronics STM32 11 | ** 12 | ***************************************************************************** 13 | */ 14 | 15 | /* Entry Point */ 16 | ENTRY(Init) 17 | 18 | /* Generate 2 segment for Loader code and device info */ 19 | PHDRS {Loader PT_LOAD ; SgInfo PT_LOAD ; } 20 | 21 | /* Highest address of the user mode stack */ 22 | _estack = ORIGIN(RAM) + LENGTH(RAM); /* end of RAM */ 23 | /* Generate a link error if heap and stack don't fit into RAM */ 24 | _Min_Heap_Size = 0x200 ; /* required amount of heap */ 25 | _Min_Stack_Size = 0x400 ; /* required amount of stack */ 26 | 27 | /* Specify the memory areas */ 28 | MEMORY 29 | { 30 | RAM (xrw) : ORIGIN = 0x20000004, LENGTH = 512K 31 | } 32 | 33 | /* Define output sections */ 34 | SECTIONS 35 | { 36 | /* The startup code goes first into FLASH */ 37 | 38 | .isr_vector : 39 | { 40 | . = . + 0x1FC; 41 | . = ALIGN(4); 42 | KEEP(*(.isr_vector)) /* Startup code */ 43 | . = ALIGN(4); 44 | } >RAM :Loader 45 | 46 | 47 | 48 | .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >RAM 49 | .ARM : { 50 | __exidx_start = .; 51 | *(.ARM.exidx*) 52 | __exidx_end = .; 53 | } >RAM :Loader 54 | 55 | .preinit_array : 56 | { 57 | PROVIDE_HIDDEN (__preinit_array_start = .); 58 | KEEP (*(.preinit_array*)) 59 | PROVIDE_HIDDEN (__preinit_array_end = .); 60 | } >RAM :Loader 61 | 62 | .init_array : 63 | { 64 | PROVIDE_HIDDEN (__init_array_start = .); 65 | KEEP (*(SORT(.init_array.*))) 66 | KEEP (*(.init_array*)) 67 | PROVIDE_HIDDEN (__init_array_end = .); 68 | } >RAM :Loader 69 | 70 | .fini_array : 71 | { 72 | PROVIDE_HIDDEN (__fini_array_start = .); 73 | KEEP (*(SORT(.fini_array.*))) 74 | KEEP (*(.fini_array*)) 75 | PROVIDE_HIDDEN (__fini_array_end = .); 76 | } >RAM :Loader 77 | 78 | /* used by the startup to initialize data */ 79 | _sidata = LOADADDR(.data); 80 | 81 | /* Initialized data sections goes into RAM, load LMA copy after code */ 82 | .data : 83 | { 84 | . = ALIGN(4); 85 | _sdata = .; /* create a global symbol at data start */ 86 | *(.data) /* .data sections */ 87 | *(.data*) /* .data* sections */ 88 | 89 | . = ALIGN(4); 90 | _edata = .; /* define a global symbol at data end */ 91 | } >RAM :Loader 92 | 93 | 94 | /* Uninitialized data section */ 95 | . = ALIGN(4); 96 | .bss : 97 | { 98 | /* This is used by the startup in order to initialize the .bss secion */ 99 | _sbss = .; /* define a global symbol at bss start */ 100 | __bss_start__ = _sbss; 101 | *(.bss) 102 | *(.bss*) 103 | *(COMMON) 104 | 105 | . = ALIGN(4); 106 | _ebss = .; /* define a global symbol at bss end */ 107 | __bss_end__ = _ebss; 108 | } >RAM :Loader 109 | 110 | /* The program code and other data goes into FLASH */ 111 | .text : 112 | { 113 | . = ALIGN(4); 114 | *(.text) /* .text sections (code) */ 115 | *(.text*) /* .text* sections (code) */ 116 | *(.glue_7) /* glue arm to thumb code */ 117 | *(.glue_7t) /* glue thumb to arm code */ 118 | *(.eh_frame) 119 | 120 | KEEP (*(.init)) 121 | KEEP (*(.fini)) 122 | 123 | . = ALIGN(4); 124 | _etext = .; /* define a global symbols at end of code */ 125 | } >RAM :Loader 126 | 127 | .Dev_info : 128 | { 129 | KEEP(*Dev_Inf.o ( .rodata* )) 130 | } :SgInfo 131 | 132 | 133 | /* Constant data goes into FLASH */ 134 | .rodata : 135 | { 136 | . = ALIGN(4); 137 | *(.rodata) /* .rodata sections (constants, strings, etc.) */ 138 | *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ 139 | . = ALIGN(4); 140 | } >RAM :Loader 141 | 142 | 143 | /* User_heap_stack section, used to check that there is enough RAM left */ 144 | ._user_heap_stack : 145 | { 146 | . = ALIGN(4); 147 | PROVIDE ( end = . ); 148 | PROVIDE ( _end = . ); 149 | . = . + _Min_Heap_Size; 150 | . = . + _Min_Stack_Size; 151 | . = ALIGN(4); 152 | } >RAM :Loader 153 | 154 | 155 | 156 | 157 | .ARM.attributes 0 : { *(.ARM.attributes) } 158 | } 159 | 160 | 161 | -------------------------------------------------------------------------------- /QSPI Drivers/GD25Q80C/quadspi.c: -------------------------------------------------------------------------------- 1 | 2 | /* USER CODE BEGIN 0 */ 3 | static uint8_t QSPI_WriteEnable(void); 4 | static uint8_t QSPI_AutoPollingMemReady(void); 5 | static uint8_t QSPI_Configuration(void); 6 | static uint8_t QSPI_ResetChip(void); 7 | /* USER CODE END 0 */ 8 | 9 | /* USER CODE BEGIN 1 */ 10 | 11 | /* QUADSPI init function */ 12 | uint8_t CSP_QUADSPI_Init(void) { 13 | //prepare QSPI peripheral for ST-Link Utility operations 14 | if (HAL_QSPI_DeInit(&hqspi) != HAL_OK) { 15 | return HAL_ERROR; 16 | } 17 | 18 | MX_QUADSPI_Init(); 19 | 20 | if (QSPI_ResetChip() != HAL_OK) { 21 | return HAL_ERROR; 22 | } 23 | 24 | HAL_Delay(1); 25 | 26 | if (QSPI_AutoPollingMemReady() != HAL_OK) { 27 | return HAL_ERROR; 28 | } 29 | 30 | if (QSPI_WriteEnable() != HAL_OK) { 31 | 32 | return HAL_ERROR; 33 | } 34 | 35 | if (QSPI_Configuration() != HAL_OK) { 36 | return HAL_ERROR; 37 | } 38 | 39 | if (QSPI_AutoPollingMemReady() != HAL_OK) { 40 | return HAL_ERROR; 41 | } 42 | return HAL_OK; 43 | } 44 | 45 | 46 | uint8_t CSP_QSPI_Erase_Chip(void) { 47 | QSPI_CommandTypeDef sCommand; 48 | 49 | 50 | if (QSPI_WriteEnable() != HAL_OK) { 51 | return HAL_ERROR; 52 | } 53 | 54 | 55 | /* Erasing Sequence --------------------------------- */ 56 | sCommand.Instruction = CHIP_ERASE_CMD; 57 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 58 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 59 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 60 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 61 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 62 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 63 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 64 | sCommand.Address = 0; 65 | sCommand.DataMode = QSPI_DATA_NONE; 66 | sCommand.DummyCycles = 0; 67 | 68 | 69 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 70 | != HAL_OK) { 71 | return HAL_ERROR; 72 | } 73 | 74 | if (QSPI_AutoPollingMemReady() != HAL_OK) { 75 | return HAL_ERROR; 76 | } 77 | 78 | return HAL_OK; 79 | } 80 | 81 | uint8_t QSPI_AutoPollingMemReady(void) { 82 | 83 | QSPI_CommandTypeDef sCommand; 84 | QSPI_AutoPollingTypeDef sConfig; 85 | 86 | /* Configure automatic polling mode to wait for memory ready ------ */ 87 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 88 | sCommand.Instruction = READ_FLAG_STATUS_REG_CMD; 89 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 90 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 91 | sCommand.DataMode = QSPI_DATA_1_LINE; 92 | sCommand.DummyCycles = 0; 93 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 94 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 95 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 96 | 97 | sConfig.Match = 0x00; 98 | sConfig.Mask = 0x01; 99 | sConfig.MatchMode = QSPI_MATCH_MODE_AND; 100 | sConfig.StatusBytesSize = 1; 101 | sConfig.Interval = 0x10; 102 | sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; 103 | 104 | if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig, 105 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 106 | return HAL_ERROR; 107 | } 108 | 109 | return HAL_OK; 110 | } 111 | 112 | static uint8_t QSPI_WriteEnable(void) { 113 | QSPI_CommandTypeDef sCommand; 114 | QSPI_AutoPollingTypeDef sConfig; 115 | 116 | QSPI_AutoPollingMemReady(); 117 | 118 | /* Enable write operations ------------------------------------------ */ 119 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 120 | sCommand.Instruction = WRITE_ENABLE_CMD; 121 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 122 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 123 | sCommand.DataMode = QSPI_DATA_NONE; 124 | sCommand.DummyCycles = 0; 125 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 126 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 127 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 128 | 129 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 130 | != HAL_OK) { 131 | return HAL_ERROR; 132 | } 133 | 134 | /* Configure automatic polling mode to wait for write enabling ---- */ 135 | sConfig.Match = 0x02; 136 | sConfig.Mask = 0x02; 137 | sConfig.MatchMode = QSPI_MATCH_MODE_AND; 138 | sConfig.StatusBytesSize = 1; 139 | sConfig.Interval = 0x10; 140 | sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; 141 | 142 | sCommand.Instruction = READ_STATUS_REG_CMD; 143 | sCommand.DataMode = QSPI_DATA_1_LINE; 144 | if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig, 145 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 146 | return HAL_ERROR; 147 | } 148 | 149 | return HAL_OK; 150 | } 151 | /*Enable quad mode and set dummy cycles count*/ 152 | uint8_t QSPI_Configuration(void) { 153 | 154 | QSPI_CommandTypeDef sCommand; 155 | uint8_t test_buffer[4] = { 0 }; 156 | /*read status register*/ 157 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 158 | sCommand.Instruction = READ_STATUS_REG_CMD; 159 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 160 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 161 | sCommand.DataMode = QSPI_DATA_1_LINE; 162 | sCommand.DummyCycles = 0; 163 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 164 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 165 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 166 | sCommand.NbData = 1; 167 | 168 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 169 | != HAL_OK) { 170 | return HAL_ERROR; 171 | } 172 | if (HAL_QSPI_Receive(&hqspi, test_buffer, 173 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 174 | return HAL_ERROR; 175 | } 176 | /*read configuration register*/ 177 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 178 | sCommand.Instruction = READ_CONFIGURATION_REG_CMD; 179 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 180 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 181 | sCommand.DataMode = QSPI_DATA_1_LINE; 182 | sCommand.DummyCycles = 0; 183 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 184 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 185 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 186 | sCommand.NbData = 1; 187 | 188 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 189 | != HAL_OK) { 190 | return HAL_ERROR; 191 | } 192 | if (HAL_QSPI_Receive(&hqspi, &(test_buffer[1]), 193 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 194 | return HAL_ERROR; 195 | } 196 | /*modify buffer to enable quad mode*/ 197 | test_buffer[0] |= 0x40; 198 | 199 | /*set dummy cycles*/ 200 | test_buffer[1] = 0x40; 201 | 202 | if (QSPI_WriteEnable() != HAL_OK) { 203 | return HAL_ERROR; 204 | } 205 | 206 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 207 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 208 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 209 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 210 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 211 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 212 | sCommand.Instruction = WRITE_STATUS_REG_CMD; 213 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 214 | sCommand.DataMode = QSPI_DATA_1_LINE; 215 | sCommand.DummyCycles = 0; 216 | sCommand.NbData = 1; 217 | 218 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 219 | != HAL_OK) { 220 | return HAL_ERROR; 221 | } 222 | 223 | if (HAL_QSPI_Transmit(&hqspi, test_buffer, 224 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 225 | Error_Handler(); 226 | return HAL_ERROR; 227 | } 228 | 229 | if (QSPI_WriteEnable() != HAL_OK) { 230 | return HAL_ERROR; 231 | } 232 | 233 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 234 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 235 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 236 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 237 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 238 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 239 | sCommand.Instruction = WRITE_CONFIGURATION_REG_CMD; 240 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 241 | sCommand.DataMode = QSPI_DATA_1_LINE; 242 | sCommand.DummyCycles = 0; 243 | sCommand.NbData = 1; 244 | 245 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 246 | != HAL_OK) { 247 | return HAL_ERROR; 248 | } 249 | 250 | if (HAL_QSPI_Transmit(&hqspi, &(test_buffer[1]), 251 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 252 | Error_Handler(); 253 | return HAL_ERROR; 254 | } 255 | return HAL_OK; 256 | } 257 | 258 | uint8_t CSP_QSPI_EraseSector(uint32_t EraseStartAddress, uint32_t EraseEndAddress) { 259 | 260 | QSPI_CommandTypeDef sCommand; 261 | 262 | EraseStartAddress = EraseStartAddress 263 | - EraseStartAddress % MEMORY_SECTOR_SIZE; 264 | 265 | /* Erasing Sequence -------------------------------------------------- */ 266 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 267 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 268 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 269 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 270 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 271 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 272 | sCommand.Instruction = SECTOR_ERASE_CMD; 273 | sCommand.AddressMode = QSPI_ADDRESS_1_LINE; 274 | 275 | sCommand.DataMode = QSPI_DATA_NONE; 276 | sCommand.DummyCycles = 0; 277 | 278 | while (EraseEndAddress >= EraseStartAddress) { 279 | sCommand.Address = (EraseStartAddress & 0x0FFFFFFF); 280 | 281 | if (QSPI_WriteEnable() != HAL_OK) { 282 | return HAL_ERROR; 283 | } 284 | 285 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 286 | != HAL_OK) { 287 | return HAL_ERROR; 288 | } 289 | EraseStartAddress += MEMORY_SECTOR_SIZE; 290 | 291 | if (QSPI_AutoPollingMemReady() != HAL_OK) { 292 | return HAL_ERROR; 293 | } 294 | } 295 | 296 | return HAL_OK; 297 | } 298 | 299 | uint8_t CSP_QSPI_WriteMemory(uint8_t* buffer, uint32_t address,uint32_t buffer_size) { 300 | 301 | QSPI_CommandTypeDef sCommand; 302 | uint32_t end_addr, current_size, current_addr; 303 | 304 | /* Calculation of the size between the write address and the end of the page */ 305 | current_addr = 0; 306 | 307 | 308 | // 309 | while (current_addr <= address) { 310 | current_addr += MEMORY_PAGE_SIZE; 311 | } 312 | current_size = current_addr - address; 313 | 314 | /* Check if the size of the data is less than the remaining place in the page */ 315 | if (current_size > buffer_size) { 316 | current_size = buffer_size; 317 | } 318 | 319 | /* Initialize the adress variables */ 320 | current_addr = address; 321 | end_addr = address + buffer_size; 322 | 323 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 324 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 325 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 326 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 327 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 328 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 329 | sCommand.Instruction = QUAD_IN_FAST_PROG_CMD; 330 | sCommand.AddressMode = QSPI_ADDRESS_1_LINE; 331 | sCommand.DataMode = QSPI_DATA_4_LINES; 332 | sCommand.NbData = buffer_size; 333 | sCommand.Address = address; 334 | sCommand.DummyCycles = 0; 335 | 336 | /* Perform the write page by page */ 337 | do { 338 | sCommand.Address = current_addr; 339 | sCommand.NbData = current_size; 340 | 341 | if (current_size == 0) { 342 | return HAL_OK; 343 | } 344 | 345 | /* Enable write operations */ 346 | if (QSPI_WriteEnable() != HAL_OK) { 347 | return HAL_ERROR; 348 | } 349 | 350 | /* Configure the command */ 351 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 352 | != HAL_OK) { 353 | 354 | return HAL_ERROR; 355 | } 356 | 357 | /* Transmission of the data */ 358 | if (HAL_QSPI_Transmit(&hqspi, buffer, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 359 | 360 | return HAL_ERROR; 361 | } 362 | 363 | /* Configure automatic polling mode to wait for end of program */ 364 | if (QSPI_AutoPollingMemReady() != HAL_OK) { 365 | return HAL_ERROR; 366 | } 367 | 368 | /* Update the address and size variables for next page programming */ 369 | current_addr += current_size; 370 | buffer += current_size; 371 | current_size = 372 | ((current_addr + MEMORY_PAGE_SIZE) > end_addr) ? 373 | (end_addr - current_addr) : MEMORY_PAGE_SIZE; 374 | } while (current_addr <= end_addr); 375 | 376 | return HAL_OK; 377 | 378 | } 379 | 380 | 381 | uint8_t CSP_QSPI_EnableMemoryMappedMode(void) { 382 | 383 | QSPI_CommandTypeDef sCommand; 384 | QSPI_MemoryMappedTypeDef sMemMappedCfg; 385 | 386 | /* Enable Memory-Mapped mode-------------------------------------------------- */ 387 | 388 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 389 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 390 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 391 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 392 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 393 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 394 | sCommand.AddressMode = QSPI_ADDRESS_1_LINE; 395 | sCommand.DataMode = QSPI_DATA_4_LINES; 396 | sCommand.NbData = 0; 397 | sCommand.Address = 0; 398 | sCommand.Instruction = QUAD_OUT_FAST_READ_CMD; 399 | sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD; 400 | 401 | sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE; 402 | 403 | if (HAL_QSPI_MemoryMapped(&hqspi, &sCommand, &sMemMappedCfg) != HAL_OK) { 404 | return HAL_ERROR; 405 | } 406 | return HAL_OK; 407 | } 408 | 409 | /*Send reset in 1,2 and 4 lines*/ 410 | uint8_t QSPI_ResetChip() { 411 | QSPI_CommandTypeDef sCommand; 412 | uint32_t temp = 0; 413 | /* Erasing Sequence -------------------------------------------------- */ 414 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 415 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 416 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 417 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 418 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 419 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 420 | sCommand.Instruction = RESET_ENABLE_CMD; 421 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 422 | sCommand.Address = 0; 423 | sCommand.DataMode = QSPI_DATA_NONE; 424 | sCommand.DummyCycles = 0; 425 | 426 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 427 | != HAL_OK) { 428 | return HAL_ERROR; 429 | } 430 | for (temp = 0; temp < 0x2f; temp++) { 431 | __NOP(); 432 | } 433 | 434 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 435 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 436 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 437 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 438 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 439 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 440 | sCommand.Instruction = RESET_EXECUTE_CMD; 441 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 442 | sCommand.Address = 0; 443 | sCommand.DataMode = QSPI_DATA_NONE; 444 | sCommand.DummyCycles = 0; 445 | 446 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 447 | != HAL_OK) { 448 | return HAL_ERROR; 449 | } 450 | 451 | /* Erasing Sequence -------------------------------------------------- */ 452 | sCommand.InstructionMode = QSPI_INSTRUCTION_2_LINES; 453 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 454 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 455 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 456 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 457 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 458 | sCommand.Instruction = RESET_ENABLE_CMD; 459 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 460 | sCommand.Address = 0; 461 | sCommand.DataMode = QSPI_DATA_NONE; 462 | sCommand.DummyCycles = 0; 463 | 464 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 465 | != HAL_OK) { 466 | return HAL_ERROR; 467 | } 468 | for (temp = 0; temp < 0x2f; temp++) { 469 | __NOP(); 470 | } 471 | 472 | sCommand.InstructionMode = QSPI_INSTRUCTION_2_LINES; 473 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 474 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 475 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 476 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 477 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 478 | sCommand.Instruction = RESET_EXECUTE_CMD; 479 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 480 | sCommand.Address = 0; 481 | sCommand.DataMode = QSPI_DATA_NONE; 482 | sCommand.DummyCycles = 0; 483 | 484 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 485 | != HAL_OK) { 486 | return HAL_ERROR; 487 | } 488 | 489 | 490 | /* Erasing Sequence -------------------------------------------------- */ 491 | sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES; 492 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 493 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 494 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 495 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 496 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 497 | sCommand.Instruction = RESET_ENABLE_CMD; 498 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 499 | sCommand.Address = 0; 500 | sCommand.DataMode = QSPI_DATA_NONE; 501 | sCommand.DummyCycles = 0; 502 | 503 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 504 | != HAL_OK) { 505 | return HAL_ERROR; 506 | } 507 | for (temp = 0; temp < 0x2f; temp++) { 508 | __NOP(); 509 | } 510 | 511 | sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES; 512 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 513 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 514 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 515 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 516 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 517 | sCommand.Instruction = RESET_EXECUTE_CMD; 518 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 519 | sCommand.Address = 0; 520 | sCommand.DataMode = QSPI_DATA_NONE; 521 | sCommand.DummyCycles = 0; 522 | 523 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 524 | != HAL_OK) { 525 | return HAL_ERROR; 526 | } 527 | 528 | 529 | return HAL_OK; 530 | } 531 | 532 | /* USER CODE END 1 */ 533 | 534 | -------------------------------------------------------------------------------- /QSPI Drivers/GD25Q80C/quadspi.h: -------------------------------------------------------------------------------- 1 | 2 | /* USER CODE BEGIN Private defines */ 3 | 4 | uint8_t CSP_QUADSPI_Init(void); 5 | uint8_t CSP_QSPI_EraseSector(uint32_t EraseStartAddress ,uint32_t EraseEndAddress); 6 | uint8_t CSP_QSPI_WriteMemory(uint8_t* buffer, uint32_t address, uint32_t buffer_size); 7 | uint8_t CSP_QSPI_EnableMemoryMappedMode(void); 8 | uint8_t CSP_QSPI_Erase_Chip (void); 9 | 10 | /* USER CODE END Private defines */ 11 | 12 | 13 | /* USER CODE BEGIN Prototypes */ 14 | 15 | /*GD25Q80C memory parameters*/ 16 | #define MEMORY_FLASH_SIZE 0x1000000 /* 128 MBits => 16MBytes */ 17 | #define MEMORY_BLOCK_SIZE 0x10000 /* 1024 sectors of 64KBytes */ 18 | #define MEMORY_SECTOR_SIZE 0x1000 /* 16384 subsectors of 4kBytes */ 19 | #define MEMORY_PAGE_SIZE 0x100 /* 262144 pages of 256 bytes */ 20 | 21 | 22 | /*GD25Q80C commands */ 23 | #define WRITE_ENABLE_CMD 0x06 24 | #define READ_STATUS_REG_CMD 0x05 25 | #define READ_FLAG_STATUS_REG_CMD 0x05//0x70 26 | #define WRITE_STATUS_REG_CMD 0x01 27 | #define SECTOR_ERASE_CMD 0x20 28 | #define CHIP_ERASE_CMD 0xC7 29 | #define QUAD_IN_FAST_PROG_CMD 0x38 30 | #define READ_CONFIGURATION_REG_CMD 0x61//0x15 31 | #define WRITE_CONFIGURATION_REG_CMD 0x65// 32 | #define QUAD_READ_IO_CMD 0xEC 33 | #define QUAD_OUT_FAST_READ_CMD 0x6B 34 | #define QPI_ENABLE_CMD 0x35 35 | #define DUMMY_CLOCK_CYCLES_READ_QUAD 8 36 | #define RESET_ENABLE_CMD 0x66 37 | #define RESET_EXECUTE_CMD 0x99 38 | #define DISABLE_QIP_MODE 0xf5 39 | 40 | /* USER CODE END Prototypes */ 41 | -------------------------------------------------------------------------------- /QSPI Drivers/IS25LP128F/quadspi.c: -------------------------------------------------------------------------------- 1 | 2 | /* USER CODE BEGIN 0 */ 3 | static uint8_t QSPI_WriteEnable(void); 4 | static uint8_t QSPI_AutoPollingMemReady(void); 5 | static uint8_t QSPI_Configuration(void); 6 | static uint8_t QSPI_ResetChip(void); 7 | /* USER CODE END 0 */ 8 | 9 | /* USER CODE BEGIN 1 */ 10 | 11 | /* QUADSPI init function */ 12 | uint8_t CSP_QUADSPI_Init(void) { 13 | //prepare QSPI peripheral for ST-Link Utility operations 14 | if (HAL_QSPI_DeInit(&hqspi) != HAL_OK) { 15 | return HAL_ERROR; 16 | } 17 | 18 | MX_QUADSPI_Init(); 19 | 20 | if (QSPI_ResetChip() != HAL_OK) { 21 | return HAL_ERROR; 22 | } 23 | 24 | HAL_Delay(1); 25 | 26 | if (QSPI_AutoPollingMemReady() != HAL_OK) { 27 | return HAL_ERROR; 28 | } 29 | 30 | if (QSPI_WriteEnable() != HAL_OK) { 31 | 32 | return HAL_ERROR; 33 | } 34 | 35 | if (QSPI_Configuration() != HAL_OK) { 36 | return HAL_ERROR; 37 | } 38 | 39 | if (QSPI_AutoPollingMemReady() != HAL_OK) { 40 | return HAL_ERROR; 41 | } 42 | return HAL_OK; 43 | } 44 | 45 | 46 | uint8_t CSP_QSPI_Erase_Chip(void) { 47 | QSPI_CommandTypeDef sCommand; 48 | 49 | 50 | if (QSPI_WriteEnable() != HAL_OK) { 51 | return HAL_ERROR; 52 | } 53 | 54 | 55 | /* Erasing Sequence --------------------------------- */ 56 | sCommand.Instruction = CHIP_ERASE_CMD; 57 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 58 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 59 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 60 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 61 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 62 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 63 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 64 | sCommand.Address = 0; 65 | sCommand.DataMode = QSPI_DATA_NONE; 66 | sCommand.DummyCycles = 0; 67 | 68 | 69 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 70 | != HAL_OK) { 71 | return HAL_ERROR; 72 | } 73 | 74 | if (QSPI_AutoPollingMemReady() != HAL_OK) { 75 | return HAL_ERROR; 76 | } 77 | 78 | return HAL_OK; 79 | } 80 | 81 | uint8_t QSPI_AutoPollingMemReady(void) { 82 | 83 | QSPI_CommandTypeDef sCommand; 84 | QSPI_AutoPollingTypeDef sConfig; 85 | 86 | /* Configure automatic polling mode to wait for memory ready ------ */ 87 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 88 | sCommand.Instruction = READ_FLAG_STATUS_REG_CMD; 89 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 90 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 91 | sCommand.DataMode = QSPI_DATA_1_LINE; 92 | sCommand.DummyCycles = 0; 93 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 94 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 95 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 96 | 97 | sConfig.Match = 0x00; 98 | sConfig.Mask = 0x01; 99 | sConfig.MatchMode = QSPI_MATCH_MODE_AND; 100 | sConfig.StatusBytesSize = 1; 101 | sConfig.Interval = 0x10; 102 | sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; 103 | 104 | if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig, 105 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 106 | return HAL_ERROR; 107 | } 108 | 109 | return HAL_OK; 110 | } 111 | 112 | static uint8_t QSPI_WriteEnable(void) { 113 | QSPI_CommandTypeDef sCommand; 114 | QSPI_AutoPollingTypeDef sConfig; 115 | 116 | QSPI_AutoPollingMemReady(); 117 | 118 | /* Enable write operations ------------------------------------------ */ 119 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 120 | sCommand.Instruction = WRITE_ENABLE_CMD; 121 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 122 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 123 | sCommand.DataMode = QSPI_DATA_NONE; 124 | sCommand.DummyCycles = 0; 125 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 126 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 127 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 128 | 129 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 130 | != HAL_OK) { 131 | return HAL_ERROR; 132 | } 133 | 134 | /* Configure automatic polling mode to wait for write enabling ---- */ 135 | sConfig.Match = 0x02; 136 | sConfig.Mask = 0x02; 137 | sConfig.MatchMode = QSPI_MATCH_MODE_AND; 138 | sConfig.StatusBytesSize = 1; 139 | sConfig.Interval = 0x10; 140 | sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; 141 | 142 | sCommand.Instruction = READ_STATUS_REG_CMD; 143 | sCommand.DataMode = QSPI_DATA_1_LINE; 144 | if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig, 145 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 146 | return HAL_ERROR; 147 | } 148 | 149 | return HAL_OK; 150 | } 151 | /*Enable quad mode and set dummy cycles count*/ 152 | uint8_t QSPI_Configuration(void) { 153 | 154 | QSPI_CommandTypeDef sCommand; 155 | uint8_t test_buffer[4] = { 0 }; 156 | /*read status register*/ 157 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 158 | sCommand.Instruction = READ_STATUS_REG_CMD; 159 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 160 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 161 | sCommand.DataMode = QSPI_DATA_1_LINE; 162 | sCommand.DummyCycles = 0; 163 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 164 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 165 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 166 | sCommand.NbData = 1; 167 | 168 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 169 | != HAL_OK) { 170 | return HAL_ERROR; 171 | } 172 | if (HAL_QSPI_Receive(&hqspi, test_buffer, 173 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 174 | return HAL_ERROR; 175 | } 176 | /*read configuration register*/ 177 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 178 | sCommand.Instruction = READ_CONFIGURATION_REG_CMD; 179 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 180 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 181 | sCommand.DataMode = QSPI_DATA_1_LINE; 182 | sCommand.DummyCycles = 0; 183 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 184 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 185 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 186 | sCommand.NbData = 1; 187 | 188 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 189 | != HAL_OK) { 190 | return HAL_ERROR; 191 | } 192 | if (HAL_QSPI_Receive(&hqspi, &(test_buffer[1]), 193 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 194 | return HAL_ERROR; 195 | } 196 | /*modify buffer to enable quad mode*/ 197 | test_buffer[0] |= 0x40; 198 | 199 | /*set dummy cycles*/ 200 | test_buffer[1] = 0x40; 201 | 202 | if (QSPI_WriteEnable() != HAL_OK) { 203 | return HAL_ERROR; 204 | } 205 | 206 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 207 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 208 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 209 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 210 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 211 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 212 | sCommand.Instruction = WRITE_STATUS_REG_CMD; 213 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 214 | sCommand.DataMode = QSPI_DATA_1_LINE; 215 | sCommand.DummyCycles = 0; 216 | sCommand.NbData = 1; 217 | 218 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 219 | != HAL_OK) { 220 | return HAL_ERROR; 221 | } 222 | 223 | if (HAL_QSPI_Transmit(&hqspi, test_buffer, 224 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 225 | Error_Handler(); 226 | return HAL_ERROR; 227 | } 228 | 229 | if (QSPI_WriteEnable() != HAL_OK) { 230 | return HAL_ERROR; 231 | } 232 | 233 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 234 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 235 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 236 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 237 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 238 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 239 | sCommand.Instruction = WRITE_CONFIGURATION_REG_CMD; 240 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 241 | sCommand.DataMode = QSPI_DATA_1_LINE; 242 | sCommand.DummyCycles = 0; 243 | sCommand.NbData = 1; 244 | 245 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 246 | != HAL_OK) { 247 | return HAL_ERROR; 248 | } 249 | 250 | if (HAL_QSPI_Transmit(&hqspi, &(test_buffer[1]), 251 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 252 | Error_Handler(); 253 | return HAL_ERROR; 254 | } 255 | return HAL_OK; 256 | } 257 | 258 | uint8_t CSP_QSPI_EraseSector(uint32_t EraseStartAddress, uint32_t EraseEndAddress) { 259 | 260 | QSPI_CommandTypeDef sCommand; 261 | 262 | EraseStartAddress = EraseStartAddress 263 | - EraseStartAddress % MEMORY_SECTOR_SIZE; 264 | 265 | /* Erasing Sequence -------------------------------------------------- */ 266 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 267 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 268 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 269 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 270 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 271 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 272 | sCommand.Instruction = SECTOR_ERASE_CMD; 273 | sCommand.AddressMode = QSPI_ADDRESS_1_LINE; 274 | 275 | sCommand.DataMode = QSPI_DATA_NONE; 276 | sCommand.DummyCycles = 0; 277 | 278 | while (EraseEndAddress >= EraseStartAddress) { 279 | sCommand.Address = (EraseStartAddress & 0x0FFFFFFF); 280 | 281 | if (QSPI_WriteEnable() != HAL_OK) { 282 | return HAL_ERROR; 283 | } 284 | 285 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 286 | != HAL_OK) { 287 | return HAL_ERROR; 288 | } 289 | EraseStartAddress += MEMORY_SECTOR_SIZE; 290 | 291 | if (QSPI_AutoPollingMemReady() != HAL_OK) { 292 | return HAL_ERROR; 293 | } 294 | } 295 | 296 | return HAL_OK; 297 | } 298 | 299 | uint8_t CSP_QSPI_WriteMemory(uint8_t* buffer, uint32_t address,uint32_t buffer_size) { 300 | 301 | QSPI_CommandTypeDef sCommand; 302 | uint32_t end_addr, current_size, current_addr; 303 | 304 | /* Calculation of the size between the write address and the end of the page */ 305 | current_addr = 0; 306 | 307 | 308 | // 309 | while (current_addr <= address) { 310 | current_addr += MEMORY_PAGE_SIZE; 311 | } 312 | current_size = current_addr - address; 313 | 314 | /* Check if the size of the data is less than the remaining place in the page */ 315 | if (current_size > buffer_size) { 316 | current_size = buffer_size; 317 | } 318 | 319 | /* Initialize the adress variables */ 320 | current_addr = address; 321 | end_addr = address + buffer_size; 322 | 323 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 324 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 325 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 326 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 327 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 328 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 329 | sCommand.Instruction = QUAD_IN_FAST_PROG_CMD; 330 | sCommand.AddressMode = QSPI_ADDRESS_1_LINE; 331 | sCommand.DataMode = QSPI_DATA_4_LINES; 332 | sCommand.NbData = buffer_size; 333 | sCommand.Address = address; 334 | sCommand.DummyCycles = 0; 335 | 336 | /* Perform the write page by page */ 337 | do { 338 | sCommand.Address = current_addr; 339 | sCommand.NbData = current_size; 340 | 341 | if (current_size == 0) { 342 | return HAL_OK; 343 | } 344 | 345 | /* Enable write operations */ 346 | if (QSPI_WriteEnable() != HAL_OK) { 347 | return HAL_ERROR; 348 | } 349 | 350 | /* Configure the command */ 351 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 352 | != HAL_OK) { 353 | 354 | return HAL_ERROR; 355 | } 356 | 357 | /* Transmission of the data */ 358 | if (HAL_QSPI_Transmit(&hqspi, buffer, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 359 | 360 | return HAL_ERROR; 361 | } 362 | 363 | /* Configure automatic polling mode to wait for end of program */ 364 | if (QSPI_AutoPollingMemReady() != HAL_OK) { 365 | return HAL_ERROR; 366 | } 367 | 368 | /* Update the address and size variables for next page programming */ 369 | current_addr += current_size; 370 | buffer += current_size; 371 | current_size = 372 | ((current_addr + MEMORY_PAGE_SIZE) > end_addr) ? 373 | (end_addr - current_addr) : MEMORY_PAGE_SIZE; 374 | } while (current_addr <= end_addr); 375 | 376 | return HAL_OK; 377 | 378 | } 379 | 380 | 381 | uint8_t CSP_QSPI_EnableMemoryMappedMode(void) { 382 | 383 | QSPI_CommandTypeDef sCommand; 384 | QSPI_MemoryMappedTypeDef sMemMappedCfg; 385 | 386 | /* Enable Memory-Mapped mode-------------------------------------------------- */ 387 | 388 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 389 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 390 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 391 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 392 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 393 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 394 | sCommand.AddressMode = QSPI_ADDRESS_1_LINE; 395 | sCommand.DataMode = QSPI_DATA_4_LINES; 396 | sCommand.NbData = 0; 397 | sCommand.Address = 0; 398 | sCommand.Instruction = QUAD_OUT_FAST_READ_CMD; 399 | sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD; 400 | 401 | sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE; 402 | 403 | if (HAL_QSPI_MemoryMapped(&hqspi, &sCommand, &sMemMappedCfg) != HAL_OK) { 404 | return HAL_ERROR; 405 | } 406 | return HAL_OK; 407 | } 408 | 409 | /*Send reset in 1,2 and 4 lines*/ 410 | uint8_t QSPI_ResetChip() { 411 | QSPI_CommandTypeDef sCommand; 412 | uint32_t temp = 0; 413 | /* Erasing Sequence -------------------------------------------------- */ 414 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 415 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 416 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 417 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 418 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 419 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 420 | sCommand.Instruction = RESET_ENABLE_CMD; 421 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 422 | sCommand.Address = 0; 423 | sCommand.DataMode = QSPI_DATA_NONE; 424 | sCommand.DummyCycles = 0; 425 | 426 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 427 | != HAL_OK) { 428 | return HAL_ERROR; 429 | } 430 | for (temp = 0; temp < 0x2f; temp++) { 431 | __NOP(); 432 | } 433 | 434 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 435 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 436 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 437 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 438 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 439 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 440 | sCommand.Instruction = RESET_EXECUTE_CMD; 441 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 442 | sCommand.Address = 0; 443 | sCommand.DataMode = QSPI_DATA_NONE; 444 | sCommand.DummyCycles = 0; 445 | 446 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 447 | != HAL_OK) { 448 | return HAL_ERROR; 449 | } 450 | 451 | /* Erasing Sequence -------------------------------------------------- */ 452 | sCommand.InstructionMode = QSPI_INSTRUCTION_2_LINES; 453 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 454 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 455 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 456 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 457 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 458 | sCommand.Instruction = RESET_ENABLE_CMD; 459 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 460 | sCommand.Address = 0; 461 | sCommand.DataMode = QSPI_DATA_NONE; 462 | sCommand.DummyCycles = 0; 463 | 464 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 465 | != HAL_OK) { 466 | return HAL_ERROR; 467 | } 468 | for (temp = 0; temp < 0x2f; temp++) { 469 | __NOP(); 470 | } 471 | 472 | sCommand.InstructionMode = QSPI_INSTRUCTION_2_LINES; 473 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 474 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 475 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 476 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 477 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 478 | sCommand.Instruction = RESET_EXECUTE_CMD; 479 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 480 | sCommand.Address = 0; 481 | sCommand.DataMode = QSPI_DATA_NONE; 482 | sCommand.DummyCycles = 0; 483 | 484 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 485 | != HAL_OK) { 486 | return HAL_ERROR; 487 | } 488 | 489 | 490 | /* Erasing Sequence -------------------------------------------------- */ 491 | sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES; 492 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 493 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 494 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 495 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 496 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 497 | sCommand.Instruction = RESET_ENABLE_CMD; 498 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 499 | sCommand.Address = 0; 500 | sCommand.DataMode = QSPI_DATA_NONE; 501 | sCommand.DummyCycles = 0; 502 | 503 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 504 | != HAL_OK) { 505 | return HAL_ERROR; 506 | } 507 | for (temp = 0; temp < 0x2f; temp++) { 508 | __NOP(); 509 | } 510 | 511 | sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES; 512 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 513 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 514 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 515 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 516 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 517 | sCommand.Instruction = RESET_EXECUTE_CMD; 518 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 519 | sCommand.Address = 0; 520 | sCommand.DataMode = QSPI_DATA_NONE; 521 | sCommand.DummyCycles = 0; 522 | 523 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 524 | != HAL_OK) { 525 | return HAL_ERROR; 526 | } 527 | 528 | 529 | return HAL_OK; 530 | } 531 | 532 | /* USER CODE END 1 */ 533 | 534 | -------------------------------------------------------------------------------- /QSPI Drivers/IS25LP128F/quadspi.h: -------------------------------------------------------------------------------- 1 | 2 | /* USER CODE BEGIN Private defines */ 3 | 4 | uint8_t CSP_QUADSPI_Init(void); 5 | uint8_t CSP_QSPI_EraseSector(uint32_t EraseStartAddress ,uint32_t EraseEndAddress); 6 | uint8_t CSP_QSPI_WriteMemory(uint8_t* buffer, uint32_t address, uint32_t buffer_size); 7 | uint8_t CSP_QSPI_EnableMemoryMappedMode(void); 8 | uint8_t CSP_QSPI_Erase_Chip (void); 9 | 10 | /* USER CODE END Private defines */ 11 | 12 | 13 | /* USER CODE BEGIN Prototypes */ 14 | 15 | /*IS25LP128F memory parameters*/ 16 | #define MEMORY_FLASH_SIZE 0x8000000 /* 128 MBits => 16MBytes */ 17 | #define MEMORY_BLOCK_SIZE 0x10000 /* 1024 sectors of 64KBytes */ 18 | #define MEMORY_SECTOR_SIZE 0x1000 /* 16384 subsectors of 4kBytes */ 19 | #define MEMORY_PAGE_SIZE 0x100 /* 262144 pages of 256 bytes */ 20 | 21 | 22 | /*IS25LP128F commands */ 23 | #define WRITE_ENABLE_CMD 0x06 24 | #define READ_STATUS_REG_CMD 0x05 25 | #define READ_FLAG_STATUS_REG_CMD 0x05//0x70 26 | #define WRITE_STATUS_REG_CMD 0x01 27 | #define SECTOR_ERASE_CMD 0x20 28 | #define CHIP_ERASE_CMD 0xC7 29 | #define QUAD_IN_FAST_PROG_CMD 0x38 30 | #define READ_CONFIGURATION_REG_CMD 0x61//0x15 31 | #define WRITE_CONFIGURATION_REG_CMD 0x65// 32 | #define QUAD_READ_IO_CMD 0xEC 33 | #define QUAD_OUT_FAST_READ_CMD 0x6B 34 | #define QPI_ENABLE_CMD 0x35 35 | #define DUMMY_CLOCK_CYCLES_READ_QUAD 8 36 | #define RESET_ENABLE_CMD 0x66 37 | #define RESET_EXECUTE_CMD 0x99 38 | #define DISABLE_QIP_MODE 0xf5 39 | 40 | /* USER CODE END Prototypes */ 41 | -------------------------------------------------------------------------------- /QSPI Drivers/MT25QL512/quadspi.c: -------------------------------------------------------------------------------- 1 | /* USER CODE BEGIN 0 */ 2 | static uint8_t QSPI_WriteEnable(void); 3 | static uint8_t QSPI_AutoPollingMemReady(uint32_t Timeout); 4 | static uint8_t QSPI_Configuration(void); 5 | static uint8_t QSPI_ResetChip(void); 6 | /* USER CODE END 0 */ 7 | 8 | /* USER CODE BEGIN 1 */ 9 | 10 | /* QUADSPI init function */ 11 | uint8_t CSP_QUADSPI_Init(void) { 12 | //prepare QSPI peripheral for ST-Link Utility operations 13 | if (HAL_QSPI_DeInit(&hqspi) != HAL_OK) { 14 | return HAL_ERROR; 15 | } 16 | 17 | MX_QUADSPI_Init(); 18 | 19 | if (QSPI_ResetChip() != HAL_OK) { 20 | return HAL_ERROR; 21 | } 22 | 23 | HAL_Delay(1); 24 | 25 | if (QSPI_AutoPollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 26 | return HAL_ERROR; 27 | } 28 | 29 | if (QSPI_WriteEnable() != HAL_OK) { 30 | 31 | return HAL_ERROR; 32 | } 33 | 34 | if (QSPI_Configuration() != HAL_OK) { 35 | return HAL_ERROR; 36 | } 37 | 38 | if (QSPI_AutoPollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 39 | return HAL_ERROR; 40 | } 41 | 42 | return HAL_OK; 43 | } 44 | 45 | 46 | uint8_t CSP_QSPI_Erase_Chip(void) { 47 | QSPI_CommandTypeDef sCommand; 48 | 49 | 50 | if (QSPI_WriteEnable() != HAL_OK) { 51 | return HAL_ERROR; 52 | } 53 | 54 | 55 | /* Erasing Sequence --------------------------------- */ 56 | sCommand.Instruction = CHIP_ERASE_CMD; 57 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 58 | sCommand.AddressSize = QSPI_ADDRESS_32_BITS; 59 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 60 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 61 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 62 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 63 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 64 | sCommand.Address = 0; 65 | sCommand.DataMode = QSPI_DATA_NONE; 66 | sCommand.DummyCycles = 0; 67 | 68 | 69 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 70 | != HAL_OK) { 71 | return HAL_ERROR; 72 | } 73 | 74 | if (QSPI_AutoPollingMemReady(QUADSPI_MAX_ERASE_TIMEOUT) != HAL_OK) { 75 | return HAL_ERROR; 76 | } 77 | 78 | 79 | return HAL_OK; 80 | } 81 | 82 | static uint8_t QSPI_AutoPollingMemReady(uint32_t Timeout) { 83 | 84 | QSPI_CommandTypeDef sCommand; 85 | QSPI_AutoPollingTypeDef sConfig; 86 | 87 | /* Configure automatic polling mode to wait for memory ready ------ */ 88 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 89 | sCommand.Instruction = READ_STATUS_REG_CMD; 90 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 91 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 92 | sCommand.DataMode = QSPI_DATA_1_LINE; 93 | sCommand.DummyCycles = 0; 94 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 95 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 96 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 97 | 98 | sConfig.Match = 0x0000; 99 | sConfig.Mask = 0x0101; 100 | sConfig.MatchMode = QSPI_MATCH_MODE_AND; 101 | sConfig.StatusBytesSize = 2; 102 | sConfig.Interval = 0x10; 103 | sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; 104 | 105 | if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig, Timeout) != HAL_OK) { 106 | return HAL_ERROR; 107 | } 108 | 109 | return HAL_OK; 110 | } 111 | 112 | static uint8_t QSPI_WriteEnable(void) { 113 | QSPI_CommandTypeDef sCommand; 114 | QSPI_AutoPollingTypeDef sConfig; 115 | 116 | /* Enable write operations ------------------------------------------ */ 117 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 118 | sCommand.Instruction = WRITE_ENABLE_CMD; 119 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 120 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 121 | sCommand.DataMode = QSPI_DATA_NONE; 122 | sCommand.DummyCycles = 0; 123 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 124 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 125 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 126 | 127 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 128 | != HAL_OK) { 129 | return HAL_ERROR; 130 | } 131 | 132 | /* Configure automatic polling mode to wait for write enabling ---- */ 133 | sConfig.Match = 0x0202; 134 | sConfig.Mask = 0x0202; 135 | sConfig.MatchMode = QSPI_MATCH_MODE_AND; 136 | sConfig.StatusBytesSize = 2; 137 | sConfig.Interval = 0x10; 138 | sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; 139 | 140 | sCommand.Instruction = READ_STATUS_REG_CMD; 141 | sCommand.DataMode = QSPI_DATA_1_LINE; 142 | if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig, 143 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 144 | return HAL_ERROR; 145 | } 146 | 147 | return HAL_OK; 148 | } 149 | 150 | /*Enable quad mode and set dummy cycles count*/ 151 | static uint8_t QSPI_Configuration(void) { 152 | 153 | QSPI_CommandTypeDef sCommand; 154 | uint16_t reg; 155 | 156 | 157 | /*enter 4 byte address*/ 158 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 159 | sCommand.Instruction = ENTER_4_BYTE_ADD_CMD; 160 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 161 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 162 | sCommand.DataMode = QSPI_DATA_NONE; 163 | sCommand.DummyCycles = 0; 164 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 165 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 166 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 167 | sCommand.NbData = 0; 168 | 169 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 170 | != HAL_OK) { 171 | return HAL_ERROR; 172 | } 173 | 174 | 175 | /*read configuration register*/ 176 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 177 | sCommand.Instruction = READ_CONFIGURATION_REG_CMD; 178 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 179 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 180 | sCommand.DataMode = QSPI_DATA_1_LINE; 181 | sCommand.DummyCycles = 0; 182 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 183 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 184 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 185 | sCommand.NbData = 2; 186 | 187 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 188 | != HAL_OK) { 189 | return HAL_ERROR; 190 | } 191 | 192 | 193 | if (HAL_QSPI_Receive(&hqspi, (uint8_t *)(®), 194 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 195 | return HAL_ERROR; 196 | } 197 | 198 | 199 | 200 | if (QSPI_WriteEnable() != HAL_OK) { 201 | 202 | return HAL_ERROR; 203 | } 204 | 205 | 206 | /*set dummy cycles*/ 207 | MODIFY_REG(reg, 0xF0F0, ((DUMMY_CLOCK_CYCLES_READ_QUAD << 4) | 208 | (DUMMY_CLOCK_CYCLES_READ_QUAD << 12))); 209 | 210 | 211 | sCommand.Instruction = WRITE_VOL_CFG_REG_CMD; 212 | 213 | 214 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 215 | != HAL_OK) { 216 | return HAL_ERROR; 217 | } 218 | 219 | if (HAL_QSPI_Transmit(&hqspi, (uint8_t *)(®), 220 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 221 | return HAL_ERROR; 222 | } 223 | return HAL_OK; 224 | } 225 | 226 | uint8_t CSP_QSPI_EraseSector(uint32_t EraseStartAddress, uint32_t EraseEndAddress) { 227 | 228 | QSPI_CommandTypeDef sCommand; 229 | 230 | EraseStartAddress = EraseStartAddress 231 | - EraseStartAddress % MEMORY_SECTOR_SIZE; 232 | 233 | /* Erasing Sequence -------------------------------------------------- */ 234 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 235 | sCommand.AddressSize = QSPI_ADDRESS_32_BITS; 236 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 237 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 238 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 239 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 240 | sCommand.Instruction = SECTOR_ERASE_CMD; 241 | sCommand.AddressMode = QSPI_ADDRESS_1_LINE; 242 | 243 | sCommand.DataMode = QSPI_DATA_NONE; 244 | sCommand.DummyCycles = 0; 245 | 246 | while (EraseEndAddress >= EraseStartAddress) { 247 | sCommand.Address = (EraseStartAddress & 0x0FFFFFFF); 248 | 249 | if (QSPI_WriteEnable() != HAL_OK) { 250 | return HAL_ERROR; 251 | } 252 | 253 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 254 | != HAL_OK) { 255 | return HAL_ERROR; 256 | } 257 | EraseStartAddress += MEMORY_SECTOR_SIZE; 258 | 259 | if (QSPI_AutoPollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 260 | return HAL_ERROR; 261 | } 262 | } 263 | 264 | return HAL_OK; 265 | } 266 | 267 | uint8_t CSP_QSPI_WriteMemory(uint8_t* buffer, uint32_t address,uint32_t buffer_size) { 268 | 269 | QSPI_CommandTypeDef sCommand; 270 | uint32_t end_addr, current_size, current_addr; 271 | 272 | /* Calculation of the size between the write address and the end of the page */ 273 | current_addr = 0; 274 | 275 | while (current_addr <= address) { 276 | current_addr += MEMORY_PAGE_SIZE; 277 | } 278 | current_size = current_addr - address; 279 | 280 | /* Check if the size of the data is less than the remaining place in the page */ 281 | if (current_size > buffer_size) { 282 | current_size = buffer_size; 283 | } 284 | 285 | /* Initialize the adress variables */ 286 | current_addr = address; 287 | end_addr = address + buffer_size; 288 | 289 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 290 | sCommand.AddressSize = QSPI_ADDRESS_32_BITS; 291 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 292 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 293 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 294 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 295 | sCommand.Instruction = QUAD_IN_FAST_PROG_CMD; 296 | sCommand.AddressMode = QSPI_ADDRESS_1_LINE; 297 | sCommand.DataMode = QSPI_DATA_4_LINES; 298 | sCommand.NbData = buffer_size; 299 | sCommand.Address = address; 300 | sCommand.DummyCycles = 0; 301 | 302 | /* Perform the write page by page */ 303 | do { 304 | sCommand.Address = current_addr; 305 | sCommand.NbData = current_size; 306 | 307 | if (current_size == 0) { 308 | return HAL_OK; 309 | } 310 | 311 | /* Enable write operations */ 312 | if (QSPI_WriteEnable() != HAL_OK) { 313 | return HAL_ERROR; 314 | } 315 | 316 | /* Configure the command */ 317 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 318 | != HAL_OK) { 319 | return HAL_ERROR; 320 | } 321 | 322 | /* Transmission of the data */ 323 | if (HAL_QSPI_Transmit(&hqspi, buffer, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 324 | return HAL_ERROR; 325 | } 326 | 327 | /* Configure automatic polling mode to wait for end of program */ 328 | if (QSPI_AutoPollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 329 | return HAL_ERROR; 330 | } 331 | 332 | /* Update the address and size variables for next page programming */ 333 | current_addr += current_size; 334 | buffer += current_size; 335 | current_size = 336 | ((current_addr + MEMORY_PAGE_SIZE) > end_addr) ? 337 | (end_addr - current_addr) : MEMORY_PAGE_SIZE; 338 | } while (current_addr <= end_addr); 339 | 340 | return HAL_OK; 341 | 342 | } 343 | 344 | 345 | uint8_t CSP_QSPI_EnableMemoryMappedMode(void) { 346 | 347 | QSPI_CommandTypeDef sCommand; 348 | QSPI_MemoryMappedTypeDef sMemMappedCfg; 349 | 350 | /* Enable Memory-Mapped mode-------------------------------------------------- */ 351 | 352 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 353 | sCommand.AddressSize = QSPI_ADDRESS_32_BITS; 354 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 355 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 356 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 357 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 358 | sCommand.AddressMode = QSPI_ADDRESS_1_LINE; 359 | sCommand.DataMode = QSPI_DATA_4_LINES; 360 | sCommand.NbData = 0; 361 | sCommand.Address = 0; 362 | sCommand.Instruction = QUAD_OUT_FAST_READ_CMD; 363 | sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD; 364 | 365 | sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE; 366 | 367 | if (HAL_QSPI_MemoryMapped(&hqspi, &sCommand, &sMemMappedCfg) != HAL_OK) { 368 | return HAL_ERROR; 369 | } 370 | return HAL_OK; 371 | } 372 | 373 | static uint8_t QSPI_ResetChip() { 374 | QSPI_CommandTypeDef sCommand; 375 | uint32_t temp = 0; 376 | /* Erasing Sequence -------------------------------------------------- */ 377 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 378 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 379 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 380 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 381 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 382 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 383 | sCommand.Instruction = RESET_ENABLE_CMD; 384 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 385 | sCommand.Address = 0; 386 | sCommand.DataMode = QSPI_DATA_NONE; 387 | sCommand.DummyCycles = 0; 388 | 389 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 390 | != HAL_OK) { 391 | return HAL_ERROR; 392 | } 393 | for (temp = 0; temp < 0x2f; temp++) { 394 | __NOP(); 395 | } 396 | 397 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 398 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 399 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 400 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 401 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 402 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 403 | sCommand.Instruction = RESET_EXECUTE_CMD; 404 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 405 | sCommand.Address = 0; 406 | sCommand.DataMode = QSPI_DATA_NONE; 407 | sCommand.DummyCycles = 0; 408 | 409 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 410 | != HAL_OK) { 411 | return HAL_ERROR; 412 | } 413 | 414 | /* Erasing Sequence -------------------------------------------------- */ 415 | sCommand.InstructionMode = QSPI_INSTRUCTION_2_LINES; 416 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 417 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 418 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 419 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 420 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 421 | sCommand.Instruction = RESET_ENABLE_CMD; 422 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 423 | sCommand.Address = 0; 424 | sCommand.DataMode = QSPI_DATA_NONE; 425 | sCommand.DummyCycles = 0; 426 | 427 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 428 | != HAL_OK) { 429 | return HAL_ERROR; 430 | } 431 | for (temp = 0; temp < 0x2f; temp++) { 432 | __NOP(); 433 | } 434 | 435 | sCommand.InstructionMode = QSPI_INSTRUCTION_2_LINES; 436 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 437 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 438 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 439 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 440 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 441 | sCommand.Instruction = RESET_EXECUTE_CMD; 442 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 443 | sCommand.Address = 0; 444 | sCommand.DataMode = QSPI_DATA_NONE; 445 | sCommand.DummyCycles = 0; 446 | 447 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 448 | != HAL_OK) { 449 | return HAL_ERROR; 450 | } 451 | 452 | /* Erasing Sequence -------------------------------------------------- */ 453 | sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES; 454 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 455 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 456 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 457 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 458 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 459 | sCommand.Instruction = RESET_ENABLE_CMD; 460 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 461 | sCommand.Address = 0; 462 | sCommand.DataMode = QSPI_DATA_NONE; 463 | sCommand.DummyCycles = 0; 464 | 465 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 466 | != HAL_OK) { 467 | return HAL_ERROR; 468 | } 469 | for (temp = 0; temp < 0x2f; temp++) { 470 | __NOP(); 471 | } 472 | 473 | sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES; 474 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 475 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 476 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 477 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 478 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 479 | sCommand.Instruction = RESET_EXECUTE_CMD; 480 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 481 | sCommand.Address = 0; 482 | sCommand.DataMode = QSPI_DATA_NONE; 483 | sCommand.DummyCycles = 0; 484 | 485 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 486 | != HAL_OK) { 487 | return HAL_ERROR; 488 | } 489 | 490 | return HAL_OK; 491 | } 492 | /* USER CODE END 1 */ 493 | -------------------------------------------------------------------------------- /QSPI Drivers/MT25QL512/quadspi.h: -------------------------------------------------------------------------------- 1 | /* USER CODE BEGIN Private defines */ 2 | 3 | uint8_t CSP_QUADSPI_Init(void); 4 | uint8_t CSP_QSPI_EraseSector(uint32_t EraseStartAddress ,uint32_t EraseEndAddress); 5 | uint8_t CSP_QSPI_WriteMemory(uint8_t* buffer, uint32_t address, uint32_t buffer_size); 6 | uint8_t CSP_QSPI_EnableMemoryMappedMode(void); 7 | uint8_t CSP_QSPI_Erase_Chip (void); 8 | 9 | /* USER CODE END Private defines */ 10 | 11 | 12 | 13 | /* USER CODE BEGIN Prototypes */ 14 | 15 | /*MT25QL512 memory parameters*/ 16 | #define MEMORY_FLASH_SIZE 0x4000000 /* 512 MBits*/ 17 | #define MEMORY_SECTOR_SIZE 0x10000 /* 64kBytes */ 18 | #define MEMORY_PAGE_SIZE 0x100 /* 256 bytes */ 19 | 20 | 21 | /*MT25QL512 commands */ 22 | #define WRITE_ENABLE_CMD 0x06 23 | #define READ_STATUS_REG_CMD 0x05 24 | #define ENTER_4_BYTE_ADD_CMD 0xB7 25 | #define WRITE_VOL_CFG_REG_CMD 0x81 26 | #define SECTOR_ERASE_CMD 0xD8 27 | #define CHIP_ERASE_CMD 0xC7 28 | #define QUAD_IN_FAST_PROG_CMD 0x32 29 | #define READ_CONFIGURATION_REG_CMD 0x85 30 | #define QUAD_OUT_FAST_READ_CMD 0x6B 31 | #define DUMMY_CLOCK_CYCLES_READ_QUAD 10 32 | #define RESET_ENABLE_CMD 0x66 33 | #define RESET_EXECUTE_CMD 0x99 34 | 35 | /*MT25QL512 timeouts*/ 36 | #define QUADSPI_MAX_ERASE_TIMEOUT 460000 /* 460s max */ 37 | 38 | /* USER CODE END Prototypes */ -------------------------------------------------------------------------------- /QSPI Drivers/MX25L51245G/quadspi.c: -------------------------------------------------------------------------------- 1 | 2 | /* USER CODE BEGIN 0 */ 3 | static uint8_t QSPI_WriteEnable(void); 4 | static uint8_t QSPI_AutoPollingMemReady(void); 5 | static uint8_t QSPI_Configuration(void); 6 | static uint8_t QSPI_ResetChip(void); 7 | /* USER CODE END 0 */ 8 | 9 | 10 | /* USER CODE BEGIN 1 */ 11 | 12 | /* QUADSPI init function */ 13 | uint8_t CSP_QUADSPI_Init(void) { 14 | //prepare QSPI peripheral for ST-Link Utility operations 15 | if (HAL_QSPI_DeInit(&hqspi) != HAL_OK) { 16 | return HAL_ERROR; 17 | } 18 | 19 | MX_QUADSPI_Init(); 20 | 21 | if (QSPI_ResetChip() != HAL_OK) { 22 | return HAL_ERROR; 23 | } 24 | 25 | HAL_Delay(1); 26 | 27 | if (QSPI_AutoPollingMemReady() != HAL_OK) { 28 | return HAL_ERROR; 29 | } 30 | 31 | if (QSPI_WriteEnable() != HAL_OK) { 32 | 33 | return HAL_ERROR; 34 | } 35 | 36 | if (QSPI_Configuration() != HAL_OK) { 37 | return HAL_ERROR; 38 | } 39 | 40 | return HAL_OK; 41 | } 42 | 43 | 44 | uint8_t CSP_QSPI_Erase_Chip(void) { 45 | QSPI_CommandTypeDef sCommand; 46 | 47 | 48 | if (QSPI_WriteEnable() != HAL_OK) { 49 | return HAL_ERROR; 50 | } 51 | 52 | 53 | /* Erasing Sequence --------------------------------- */ 54 | sCommand.Instruction = CHIP_ERASE_CMD; 55 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 56 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 57 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 58 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 59 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 60 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 61 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 62 | sCommand.Address = 0; 63 | sCommand.DataMode = QSPI_DATA_NONE; 64 | sCommand.DummyCycles = 0; 65 | 66 | 67 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 68 | != HAL_OK) { 69 | return HAL_ERROR; 70 | } 71 | 72 | if (QSPI_AutoPollingMemReady() != HAL_OK) { 73 | return HAL_ERROR; 74 | } 75 | 76 | return HAL_OK; 77 | } 78 | 79 | uint8_t QSPI_AutoPollingMemReady(void) { 80 | 81 | QSPI_CommandTypeDef sCommand; 82 | QSPI_AutoPollingTypeDef sConfig; 83 | 84 | /* Configure automatic polling mode to wait for memory ready ------ */ 85 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 86 | sCommand.Instruction = READ_FLAG_STATUS_REG_CMD; 87 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 88 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 89 | sCommand.DataMode = QSPI_DATA_1_LINE; 90 | sCommand.DummyCycles = 0; 91 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 92 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 93 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 94 | 95 | sConfig.Match = 0x8080; 96 | sConfig.Mask = 0x8080; 97 | sConfig.MatchMode = QSPI_MATCH_MODE_AND; 98 | sConfig.StatusBytesSize = 2; 99 | sConfig.Interval = 0x10; 100 | sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; 101 | 102 | if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig, 103 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 104 | return HAL_ERROR; 105 | } 106 | 107 | return HAL_OK; 108 | } 109 | 110 | static uint8_t QSPI_WriteEnable(void) { 111 | QSPI_CommandTypeDef sCommand; 112 | QSPI_AutoPollingTypeDef sConfig; 113 | 114 | /* Enable write operations ------------------------------------------ */ 115 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 116 | sCommand.Instruction = WRITE_ENABLE_CMD; 117 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 118 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 119 | sCommand.DataMode = QSPI_DATA_NONE; 120 | sCommand.DummyCycles = 0; 121 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 122 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 123 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 124 | 125 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 126 | != HAL_OK) { 127 | return HAL_ERROR; 128 | } 129 | 130 | /* Configure automatic polling mode to wait for write enabling ---- */ 131 | sConfig.Match = 0x02; 132 | sConfig.Mask = 0x02; 133 | sConfig.MatchMode = QSPI_MATCH_MODE_AND; 134 | sConfig.StatusBytesSize = 1; 135 | sConfig.Interval = 0x10; 136 | sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; 137 | 138 | sCommand.Instruction = READ_STATUS_REG_CMD; 139 | sCommand.DataMode = QSPI_DATA_1_LINE; 140 | if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig, 141 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 142 | return HAL_ERROR; 143 | } 144 | 145 | return HAL_OK; 146 | } 147 | /*Enable quad mode and set dummy cycles count*/ 148 | uint8_t QSPI_Configuration(void) { 149 | 150 | QSPI_CommandTypeDef sCommand; 151 | uint8_t test_buffer[4] = { 0 }; 152 | /*read status register*/ 153 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 154 | sCommand.Instruction = READ_STATUS_REG_CMD; 155 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 156 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 157 | sCommand.DataMode = QSPI_DATA_1_LINE; 158 | sCommand.DummyCycles = 0; 159 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 160 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 161 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 162 | sCommand.NbData = 1; 163 | 164 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 165 | != HAL_OK) { 166 | return HAL_ERROR; 167 | } 168 | if (HAL_QSPI_Receive(&hqspi, test_buffer, 169 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 170 | return HAL_ERROR; 171 | } 172 | /*read configuration register*/ 173 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 174 | sCommand.Instruction = READ_CONFIGURATION_REG_CMD; 175 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 176 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 177 | sCommand.DataMode = QSPI_DATA_1_LINE; 178 | sCommand.DummyCycles = 0; 179 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 180 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 181 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 182 | sCommand.NbData = 1; 183 | 184 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 185 | != HAL_OK) { 186 | return HAL_ERROR; 187 | } 188 | if (HAL_QSPI_Receive(&hqspi, &(test_buffer[1]), 189 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 190 | return HAL_ERROR; 191 | } 192 | /*modify buffer to enable quad mode*/ 193 | test_buffer[0] |= 0x40; 194 | 195 | /*set dummy cycles*/ 196 | test_buffer[1] |= 0xC0; 197 | 198 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 199 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 200 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 201 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 202 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 203 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 204 | sCommand.Instruction = WRITE_STATUS_REG_CMD; 205 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 206 | sCommand.DataMode = QSPI_DATA_1_LINE; 207 | sCommand.DummyCycles = 0; 208 | sCommand.NbData = 2; 209 | 210 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 211 | != HAL_OK) { 212 | return HAL_ERROR; 213 | } 214 | 215 | if (HAL_QSPI_Transmit(&hqspi, test_buffer, 216 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 217 | Error_Handler(); 218 | return HAL_ERROR; 219 | } 220 | return HAL_OK; 221 | } 222 | 223 | uint8_t CSP_QSPI_EraseSector(uint32_t EraseStartAddress, uint32_t EraseEndAddress) { 224 | 225 | QSPI_CommandTypeDef sCommand; 226 | 227 | EraseStartAddress = EraseStartAddress 228 | - EraseStartAddress % MEMORY_SECTOR_SIZE; 229 | 230 | /* Erasing Sequence -------------------------------------------------- */ 231 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 232 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 233 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 234 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 235 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 236 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 237 | sCommand.Instruction = SECTOR_ERASE_CMD; 238 | sCommand.AddressMode = QSPI_ADDRESS_1_LINE; 239 | 240 | sCommand.DataMode = QSPI_DATA_NONE; 241 | sCommand.DummyCycles = 0; 242 | 243 | while (EraseEndAddress >= EraseStartAddress) { 244 | sCommand.Address = (EraseStartAddress & 0x0FFFFFFF); 245 | 246 | if (QSPI_WriteEnable() != HAL_OK) { 247 | return HAL_ERROR; 248 | } 249 | 250 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 251 | != HAL_OK) { 252 | return HAL_ERROR; 253 | } 254 | EraseStartAddress += MEMORY_SECTOR_SIZE; 255 | 256 | if (QSPI_AutoPollingMemReady() != HAL_OK) { 257 | return HAL_ERROR; 258 | } 259 | } 260 | 261 | return HAL_OK; 262 | } 263 | 264 | uint8_t CSP_QSPI_WriteMemory(uint8_t* buffer, uint32_t address,uint32_t buffer_size) { 265 | 266 | QSPI_CommandTypeDef sCommand; 267 | uint32_t end_addr, current_size, current_addr; 268 | 269 | /* Calculation of the size between the write address and the end of the page */ 270 | current_addr = 0; 271 | 272 | 273 | // 274 | while (current_addr <= address) { 275 | current_addr += MEMORY_PAGE_SIZE; 276 | } 277 | current_size = current_addr - address; 278 | 279 | /* Check if the size of the data is less than the remaining place in the page */ 280 | if (current_size > buffer_size) { 281 | current_size = buffer_size; 282 | } 283 | 284 | /* Initialize the adress variables */ 285 | current_addr = address; 286 | end_addr = address + buffer_size; 287 | 288 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 289 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 290 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 291 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 292 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 293 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 294 | sCommand.Instruction = QUAD_IN_FAST_PROG_CMD; 295 | sCommand.AddressMode = QSPI_ADDRESS_4_LINES; 296 | sCommand.DataMode = QSPI_DATA_4_LINES; 297 | sCommand.NbData = buffer_size; 298 | sCommand.Address = address; 299 | sCommand.DummyCycles = 0; 300 | 301 | /* Perform the write page by page */ 302 | do { 303 | sCommand.Address = current_addr; 304 | sCommand.NbData = current_size; 305 | 306 | if (current_size == 0) { 307 | return HAL_OK; 308 | } 309 | 310 | /* Enable write operations */ 311 | if (QSPI_WriteEnable() != HAL_OK) { 312 | return HAL_ERROR; 313 | } 314 | 315 | /* Configure the command */ 316 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 317 | != HAL_OK) { 318 | 319 | return HAL_ERROR; 320 | } 321 | 322 | /* Transmission of the data */ 323 | if (HAL_QSPI_Transmit(&hqspi, buffer, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 324 | 325 | return HAL_ERROR; 326 | } 327 | 328 | /* Configure automatic polling mode to wait for end of program */ 329 | if (QSPI_AutoPollingMemReady() != HAL_OK) { 330 | return HAL_ERROR; 331 | } 332 | 333 | /* Update the address and size variables for next page programming */ 334 | current_addr += current_size; 335 | buffer += current_size; 336 | current_size = 337 | ((current_addr + MEMORY_PAGE_SIZE) > end_addr) ? 338 | (end_addr - current_addr) : MEMORY_PAGE_SIZE; 339 | } while (current_addr <= end_addr); 340 | 341 | return HAL_OK; 342 | 343 | } 344 | 345 | 346 | uint8_t CSP_QSPI_EnableMemoryMappedMode(void) { 347 | 348 | QSPI_CommandTypeDef sCommand; 349 | QSPI_MemoryMappedTypeDef sMemMappedCfg; 350 | 351 | /* Enable Memory-Mapped mode-------------------------------------------------- */ 352 | 353 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 354 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 355 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 356 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 357 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 358 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 359 | sCommand.AddressMode = QSPI_ADDRESS_1_LINE; 360 | sCommand.DataMode = QSPI_DATA_4_LINES; 361 | sCommand.NbData = 0; 362 | sCommand.Address = 0; 363 | sCommand.Instruction = QUAD_OUT_FAST_READ_CMD; 364 | sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD; 365 | 366 | sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE; 367 | 368 | if (HAL_QSPI_MemoryMapped(&hqspi, &sCommand, &sMemMappedCfg) != HAL_OK) { 369 | return HAL_ERROR; 370 | } 371 | return HAL_OK; 372 | } 373 | 374 | /*Send reset in 1,2 and 4 lines*/ 375 | uint8_t QSPI_ResetChip() { 376 | QSPI_CommandTypeDef sCommand; 377 | uint32_t temp = 0; 378 | /* Erasing Sequence -------------------------------------------------- */ 379 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 380 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 381 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 382 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 383 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 384 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 385 | sCommand.Instruction = RESET_ENABLE_CMD; 386 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 387 | sCommand.Address = 0; 388 | sCommand.DataMode = QSPI_DATA_NONE; 389 | sCommand.DummyCycles = 0; 390 | 391 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 392 | != HAL_OK) { 393 | return HAL_ERROR; 394 | } 395 | for (temp = 0; temp < 0x2f; temp++) { 396 | __NOP(); 397 | } 398 | 399 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 400 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 401 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 402 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 403 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 404 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 405 | sCommand.Instruction = RESET_EXECUTE_CMD; 406 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 407 | sCommand.Address = 0; 408 | sCommand.DataMode = QSPI_DATA_NONE; 409 | sCommand.DummyCycles = 0; 410 | 411 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 412 | != HAL_OK) { 413 | return HAL_ERROR; 414 | } 415 | 416 | /* Erasing Sequence -------------------------------------------------- */ 417 | sCommand.InstructionMode = QSPI_INSTRUCTION_2_LINES; 418 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 419 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 420 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 421 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 422 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 423 | sCommand.Instruction = RESET_ENABLE_CMD; 424 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 425 | sCommand.Address = 0; 426 | sCommand.DataMode = QSPI_DATA_NONE; 427 | sCommand.DummyCycles = 0; 428 | 429 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 430 | != HAL_OK) { 431 | return HAL_ERROR; 432 | } 433 | for (temp = 0; temp < 0x2f; temp++) { 434 | __NOP(); 435 | } 436 | 437 | sCommand.InstructionMode = QSPI_INSTRUCTION_2_LINES; 438 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 439 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 440 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 441 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 442 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 443 | sCommand.Instruction = RESET_EXECUTE_CMD; 444 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 445 | sCommand.Address = 0; 446 | sCommand.DataMode = QSPI_DATA_NONE; 447 | sCommand.DummyCycles = 0; 448 | 449 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 450 | != HAL_OK) { 451 | return HAL_ERROR; 452 | } 453 | 454 | 455 | /* Erasing Sequence -------------------------------------------------- */ 456 | sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES; 457 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 458 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 459 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 460 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 461 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 462 | sCommand.Instruction = RESET_ENABLE_CMD; 463 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 464 | sCommand.Address = 0; 465 | sCommand.DataMode = QSPI_DATA_NONE; 466 | sCommand.DummyCycles = 0; 467 | 468 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 469 | != HAL_OK) { 470 | return HAL_ERROR; 471 | } 472 | for (temp = 0; temp < 0x2f; temp++) { 473 | __NOP(); 474 | } 475 | 476 | sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES; 477 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 478 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 479 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 480 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 481 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 482 | sCommand.Instruction = RESET_EXECUTE_CMD; 483 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 484 | sCommand.Address = 0; 485 | sCommand.DataMode = QSPI_DATA_NONE; 486 | sCommand.DummyCycles = 0; 487 | 488 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 489 | != HAL_OK) { 490 | return HAL_ERROR; 491 | } 492 | 493 | 494 | return HAL_OK; 495 | } 496 | 497 | /* USER CODE END 1 */ -------------------------------------------------------------------------------- /QSPI Drivers/MX25L51245G/quadspi.h: -------------------------------------------------------------------------------- 1 | /* USER CODE BEGIN Private defines */ 2 | 3 | uint8_t CSP_QUADSPI_Init(void); 4 | uint8_t CSP_QSPI_EraseSector(uint32_t EraseStartAddress ,uint32_t EraseEndAddress); 5 | uint8_t CSP_QSPI_WriteMemory(uint8_t* buffer, uint32_t address, uint32_t buffer_size); 6 | uint8_t CSP_QSPI_EnableMemoryMappedMode(void); 7 | uint8_t CSP_QSPI_Erase_Chip (void); 8 | 9 | /* USER CODE END Private defines */ 10 | 11 | 12 | /* USER CODE BEGIN Prototypes */ 13 | 14 | /*MX25L512 memory parameters*/ 15 | #define MEMORY_FLASH_SIZE 0x4000000 /* 512 MBits => 64MBytes */ 16 | #define MEMORY_BLOCK_SIZE 0x10000 /* 1024 sectors of 64KBytes */ 17 | #define MEMORY_SECTOR_SIZE 0x1000 /* 16384 subsectors of 4kBytes */ 18 | #define MEMORY_PAGE_SIZE 0x100 /* 262144 pages of 256 bytes */ 19 | 20 | 21 | /*MX25L512 commands */ 22 | #define WRITE_ENABLE_CMD 0x06 23 | #define READ_STATUS_REG_CMD 0x05 24 | #define READ_FLAG_STATUS_REG_CMD 0x70 25 | #define WRITE_STATUS_REG_CMD 0x01 26 | #define SECTOR_ERASE_CMD 0x20 27 | #define CHIP_ERASE_CMD 0xC7 28 | #define QUAD_IN_FAST_PROG_CMD 0x38 29 | #define READ_CONFIGURATION_REG_CMD 0x15 30 | #define QUAD_READ_IO_CMD 0xEC 31 | #define QUAD_OUT_FAST_READ_CMD 0x6B 32 | #define QPI_ENABLE_CMD 0x35 33 | #define DUMMY_CLOCK_CYCLES_READ_QUAD 10 34 | #define RESET_ENABLE_CMD 0x66 35 | #define RESET_EXECUTE_CMD 0x99 36 | #define DISABLE_QIP_MODE 0xf5 37 | 38 | /* USER CODE END Prototypes */ 39 | -------------------------------------------------------------------------------- /QSPI Drivers/N25Q256A/quadspi.c: -------------------------------------------------------------------------------- 1 | 2 | /* USER CODE BEGIN 0 */ 3 | static uint8_t QSPI_WriteEnable(void); 4 | static uint8_t QSPI_AutoPollingMemReady(void); 5 | static uint8_t QSPI_Configuration(void); 6 | static uint8_t QSPI_ResetChip(void); 7 | /* USER CODE END 0 */ 8 | 9 | 10 | /* USER CODE BEGIN 1 */ 11 | 12 | /* QUADSPI init function */ 13 | uint8_t CSP_QUADSPI_Init(void) { 14 | //prepare QSPI peripheral for ST-Link Utility operations 15 | if (HAL_QSPI_DeInit(&hqspi) != HAL_OK) { 16 | return HAL_ERROR; 17 | } 18 | 19 | MX_QUADSPI_Init(); 20 | 21 | if (QSPI_ResetChip() != HAL_OK) { 22 | return HAL_ERROR; 23 | } 24 | 25 | HAL_Delay(1); 26 | 27 | if (QSPI_AutoPollingMemReady() != HAL_OK) { 28 | return HAL_ERROR; 29 | } 30 | 31 | if (QSPI_WriteEnable() != HAL_OK) { 32 | 33 | return HAL_ERROR; 34 | } 35 | 36 | if (QSPI_Configuration() != HAL_OK) { 37 | return HAL_ERROR; 38 | } 39 | 40 | return HAL_OK; 41 | } 42 | 43 | 44 | uint8_t CSP_QSPI_Erase_Chip(void) { 45 | QSPI_CommandTypeDef sCommand; 46 | 47 | 48 | if (QSPI_WriteEnable() != HAL_OK) { 49 | return HAL_ERROR; 50 | } 51 | 52 | 53 | /* Erasing Sequence --------------------------------- */ 54 | sCommand.Instruction = CHIP_ERASE_CMD; 55 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 56 | sCommand.AddressSize = QSPI_ADDRESS_32_BITS; 57 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 58 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 59 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 60 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 61 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 62 | sCommand.Address = 0; 63 | sCommand.DataMode = QSPI_DATA_NONE; 64 | sCommand.DummyCycles = 0; 65 | 66 | 67 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 68 | != HAL_OK) { 69 | return HAL_ERROR; 70 | } 71 | 72 | if (QSPI_AutoPollingMemReady() != HAL_OK) { 73 | return HAL_ERROR; 74 | } 75 | 76 | return HAL_OK; 77 | } 78 | 79 | uint8_t QSPI_AutoPollingMemReady(void) { 80 | 81 | QSPI_CommandTypeDef sCommand; 82 | QSPI_AutoPollingTypeDef sConfig; 83 | 84 | /* Configure automatic polling mode to wait for memory ready ------ */ 85 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 86 | sCommand.Instruction = READ_STATUS_REG_CMD; 87 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 88 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 89 | sCommand.DataMode = QSPI_DATA_1_LINE; 90 | sCommand.DummyCycles = 0; 91 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 92 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 93 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 94 | 95 | sConfig.Match = 0x00; 96 | sConfig.Mask = 0x01; 97 | sConfig.MatchMode = QSPI_MATCH_MODE_AND; 98 | sConfig.StatusBytesSize = 1; 99 | sConfig.Interval = 0x10; 100 | sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; 101 | 102 | if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig, 103 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 104 | return HAL_ERROR; 105 | } 106 | 107 | return HAL_OK; 108 | } 109 | 110 | static uint8_t QSPI_WriteEnable(void) { 111 | QSPI_CommandTypeDef sCommand; 112 | QSPI_AutoPollingTypeDef sConfig; 113 | 114 | /* Enable write operations ------------------------------------------ */ 115 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 116 | sCommand.Instruction = WRITE_ENABLE_CMD; 117 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 118 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 119 | sCommand.DataMode = QSPI_DATA_NONE; 120 | sCommand.DummyCycles = 0; 121 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 122 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 123 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 124 | 125 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 126 | != HAL_OK) { 127 | return HAL_ERROR; 128 | } 129 | 130 | /* Configure automatic polling mode to wait for write enabling ---- */ 131 | sConfig.Match = 0x02; 132 | sConfig.Mask = 0x02; 133 | sConfig.MatchMode = QSPI_MATCH_MODE_AND; 134 | sConfig.StatusBytesSize = 1; 135 | sConfig.Interval = 0x10; 136 | sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; 137 | 138 | sCommand.Instruction = READ_STATUS_REG_CMD; 139 | sCommand.DataMode = QSPI_DATA_1_LINE; 140 | if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig, 141 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 142 | return HAL_ERROR; 143 | } 144 | 145 | return HAL_OK; 146 | } 147 | /*Enable quad mode and set dummy cycles count*/ 148 | uint8_t QSPI_Configuration(void) { 149 | 150 | QSPI_CommandTypeDef sCommand; 151 | uint8_t reg; 152 | 153 | 154 | /*enter 4 byte address*/ 155 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 156 | sCommand.Instruction = ENTER_4_BYTE_ADD_CMD; 157 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 158 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 159 | sCommand.DataMode = QSPI_DATA_NONE; 160 | sCommand.DummyCycles = 0; 161 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 162 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 163 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 164 | sCommand.NbData = 0; 165 | 166 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 167 | != HAL_OK) { 168 | return HAL_ERROR; 169 | } 170 | 171 | 172 | 173 | 174 | /*read configuration register*/ 175 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 176 | sCommand.Instruction = READ_CONFIGURATION_REG_CMD; 177 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 178 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 179 | sCommand.DataMode = QSPI_DATA_1_LINE; 180 | sCommand.DummyCycles = 0; 181 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 182 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 183 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 184 | sCommand.NbData = 1; 185 | 186 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 187 | != HAL_OK) { 188 | return HAL_ERROR; 189 | } 190 | 191 | 192 | if (HAL_QSPI_Receive(&hqspi, ®, 193 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 194 | return HAL_ERROR; 195 | } 196 | 197 | 198 | 199 | if (QSPI_WriteEnable() != HAL_OK) { 200 | 201 | return HAL_ERROR; 202 | } 203 | 204 | 205 | /*set dummy cycles*/ 206 | MODIFY_REG(reg, 0xF0, (DUMMY_CLOCK_CYCLES_READ_QUAD << POSITION_VAL(0xF0))); 207 | 208 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 209 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 210 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 211 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 212 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 213 | sCommand.Instruction = WRITE_VOL_CFG_REG_CMD; 214 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 215 | sCommand.DataMode = QSPI_DATA_1_LINE; 216 | sCommand.DummyCycles = 0; 217 | sCommand.NbData = 1; 218 | 219 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 220 | != HAL_OK) { 221 | return HAL_ERROR; 222 | } 223 | 224 | if (HAL_QSPI_Transmit(&hqspi, ®, 225 | HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 226 | Error_Handler(); 227 | return HAL_ERROR; 228 | } 229 | return HAL_OK; 230 | } 231 | 232 | uint8_t CSP_QSPI_EraseSector(uint32_t EraseStartAddress, uint32_t EraseEndAddress) { 233 | 234 | QSPI_CommandTypeDef sCommand; 235 | 236 | EraseStartAddress = EraseStartAddress 237 | - EraseStartAddress % MEMORY_SECTOR_SIZE; 238 | 239 | /* Erasing Sequence -------------------------------------------------- */ 240 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 241 | sCommand.AddressSize = QSPI_ADDRESS_32_BITS; 242 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 243 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 244 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 245 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 246 | sCommand.Instruction = SECTOR_ERASE_CMD; 247 | sCommand.AddressMode = QSPI_ADDRESS_1_LINE; 248 | 249 | sCommand.DataMode = QSPI_DATA_NONE; 250 | sCommand.DummyCycles = 0; 251 | 252 | while (EraseEndAddress >= EraseStartAddress) { 253 | sCommand.Address = (EraseStartAddress & 0x0FFFFFFF); 254 | 255 | if (QSPI_WriteEnable() != HAL_OK) { 256 | return HAL_ERROR; 257 | } 258 | 259 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 260 | != HAL_OK) { 261 | return HAL_ERROR; 262 | } 263 | EraseStartAddress += MEMORY_SECTOR_SIZE; 264 | 265 | if (QSPI_AutoPollingMemReady() != HAL_OK) { 266 | return HAL_ERROR; 267 | } 268 | } 269 | 270 | return HAL_OK; 271 | } 272 | 273 | uint8_t CSP_QSPI_WriteMemory(uint8_t* buffer, uint32_t address,uint32_t buffer_size) { 274 | 275 | QSPI_CommandTypeDef sCommand; 276 | uint32_t end_addr, current_size, current_addr; 277 | 278 | /* Calculation of the size between the write address and the end of the page */ 279 | current_addr = 0; 280 | 281 | 282 | // 283 | while (current_addr <= address) { 284 | current_addr += MEMORY_PAGE_SIZE; 285 | } 286 | current_size = current_addr - address; 287 | 288 | /* Check if the size of the data is less than the remaining place in the page */ 289 | if (current_size > buffer_size) { 290 | current_size = buffer_size; 291 | } 292 | 293 | /* Initialize the adress variables */ 294 | current_addr = address; 295 | end_addr = address + buffer_size; 296 | 297 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 298 | sCommand.AddressSize = QSPI_ADDRESS_32_BITS; 299 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 300 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 301 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 302 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 303 | sCommand.Instruction = QUAD_IN_FAST_PROG_CMD; 304 | sCommand.AddressMode = QSPI_ADDRESS_1_LINE; 305 | sCommand.DataMode = QSPI_DATA_4_LINES; 306 | sCommand.NbData = buffer_size; 307 | sCommand.Address = address; 308 | sCommand.DummyCycles = 0; 309 | 310 | /* Perform the write page by page */ 311 | do { 312 | sCommand.Address = current_addr; 313 | sCommand.NbData = current_size; 314 | 315 | if (current_size == 0) { 316 | return HAL_OK; 317 | } 318 | 319 | /* Enable write operations */ 320 | if (QSPI_WriteEnable() != HAL_OK) { 321 | return HAL_ERROR; 322 | } 323 | 324 | /* Configure the command */ 325 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 326 | != HAL_OK) { 327 | 328 | return HAL_ERROR; 329 | } 330 | 331 | /* Transmission of the data */ 332 | if (HAL_QSPI_Transmit(&hqspi, buffer, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { 333 | 334 | return HAL_ERROR; 335 | } 336 | 337 | /* Configure automatic polling mode to wait for end of program */ 338 | if (QSPI_AutoPollingMemReady() != HAL_OK) { 339 | return HAL_ERROR; 340 | } 341 | 342 | /* Update the address and size variables for next page programming */ 343 | current_addr += current_size; 344 | buffer += current_size; 345 | current_size = 346 | ((current_addr + MEMORY_PAGE_SIZE) > end_addr) ? 347 | (end_addr - current_addr) : MEMORY_PAGE_SIZE; 348 | } while (current_addr <= end_addr); 349 | 350 | return HAL_OK; 351 | 352 | } 353 | 354 | 355 | uint8_t CSP_QSPI_EnableMemoryMappedMode(void) { 356 | 357 | QSPI_CommandTypeDef sCommand; 358 | QSPI_MemoryMappedTypeDef sMemMappedCfg; 359 | 360 | /* Enable Memory-Mapped mode-------------------------------------------------- */ 361 | 362 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 363 | sCommand.AddressSize = QSPI_ADDRESS_32_BITS; 364 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 365 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 366 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 367 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 368 | sCommand.AddressMode = QSPI_ADDRESS_4_LINES; 369 | sCommand.DataMode = QSPI_DATA_4_LINES; 370 | sCommand.NbData = 0; 371 | sCommand.Address = 0; 372 | sCommand.Instruction = QUAD_OUT_FAST_READ_CMD; 373 | sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD; 374 | 375 | sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE; 376 | 377 | if (HAL_QSPI_MemoryMapped(&hqspi, &sCommand, &sMemMappedCfg) != HAL_OK) { 378 | return HAL_ERROR; 379 | } 380 | return HAL_OK; 381 | } 382 | 383 | uint8_t QSPI_ResetChip() { 384 | QSPI_CommandTypeDef sCommand; 385 | uint32_t temp = 0; 386 | /* Erasing Sequence -------------------------------------------------- */ 387 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 388 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 389 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 390 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 391 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 392 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 393 | sCommand.Instruction = RESET_ENABLE_CMD; 394 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 395 | sCommand.Address = 0; 396 | sCommand.DataMode = QSPI_DATA_NONE; 397 | sCommand.DummyCycles = 0; 398 | 399 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 400 | != HAL_OK) { 401 | return HAL_ERROR; 402 | } 403 | for (temp = 0; temp < 0x2f; temp++) { 404 | __NOP(); 405 | } 406 | 407 | sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; 408 | sCommand.AddressSize = QSPI_ADDRESS_24_BITS; 409 | sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 410 | sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; 411 | sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 412 | sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 413 | sCommand.Instruction = RESET_EXECUTE_CMD; 414 | sCommand.AddressMode = QSPI_ADDRESS_NONE; 415 | sCommand.Address = 0; 416 | sCommand.DataMode = QSPI_DATA_NONE; 417 | sCommand.DummyCycles = 0; 418 | 419 | if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) 420 | != HAL_OK) { 421 | return HAL_ERROR; 422 | } 423 | return HAL_OK; 424 | } 425 | 426 | /* USER CODE END 1 */ -------------------------------------------------------------------------------- /QSPI Drivers/N25Q256A/quadspi.h: -------------------------------------------------------------------------------- 1 | /* USER CODE BEGIN Private defines */ 2 | 3 | uint8_t CSP_QUADSPI_Init(void); 4 | uint8_t CSP_QSPI_EraseSector(uint32_t EraseStartAddress ,uint32_t EraseEndAddress); 5 | uint8_t CSP_QSPI_WriteMemory(uint8_t* buffer, uint32_t address, uint32_t buffer_size); 6 | uint8_t CSP_QSPI_EnableMemoryMappedMode(void); 7 | uint8_t CSP_QSPI_Erase_Chip (void); 8 | 9 | /* USER CODE END Private defines */ 10 | 11 | 12 | /* USER CODE BEGIN Prototypes */ 13 | 14 | /*N25Q256A memory parameters*/ 15 | #define MEMORY_FLASH_SIZE 0x2000000 /* 256 MBits*/ 16 | #define MEMORY_SECTOR_SIZE 0x10000 /* 64kBytes */ 17 | #define MEMORY_PAGE_SIZE 0x100 /* 256 bytes */ 18 | 19 | 20 | /*N25Q256A commands */ 21 | #define WRITE_ENABLE_CMD 0x06 22 | #define READ_STATUS_REG_CMD 0x05 23 | #define ENTER_4_BYTE_ADD_CMD 0xB7 24 | #define WRITE_VOL_CFG_REG_CMD 0x81 25 | #define SECTOR_ERASE_CMD 0xD8 26 | #define CHIP_ERASE_CMD 0xC7 27 | #define QUAD_IN_FAST_PROG_CMD 0x32 28 | #define READ_CONFIGURATION_REG_CMD 0x85 29 | #define QUAD_OUT_FAST_READ_CMD 0xEB 30 | #define DUMMY_CLOCK_CYCLES_READ_QUAD 10 31 | #define RESET_ENABLE_CMD 0x66 32 | #define RESET_EXECUTE_CMD 0x99 33 | 34 | /* USER CODE END Prototypes */ -------------------------------------------------------------------------------- /QSPI testing/main_test.c: -------------------------------------------------------------------------------- 1 | /* USER CODE BEGIN 0 */ 2 | #include 3 | #define SECTORS_COUNT 100 4 | /* USER CODE END 0 */ 5 | 6 | 7 | /* USER CODE BEGIN 2 */ 8 | 9 | uint8_t buffer_test[MEMORY_SECTOR_SIZE]; 10 | uint32_t var = 0; 11 | 12 | CSP_QUADSPI_Init(); 13 | 14 | for (var = 0; var < MEMORY_SECTOR_SIZE; var++) { 15 | buffer_test[var] = (var & 0xff); 16 | } 17 | 18 | for (var = 0; var < SECTORS_COUNT; var++) { 19 | 20 | if (CSP_QSPI_EraseSector(var * MEMORY_SECTOR_SIZE, 21 | (var + 1) * MEMORY_SECTOR_SIZE - 1) != HAL_OK) { 22 | 23 | while (1) 24 | ; //breakpoint - error detected 25 | } 26 | 27 | if (CSP_QSPI_WriteMemory(buffer_test, var * MEMORY_SECTOR_SIZE, 28 | sizeof(buffer_test)) != HAL_OK) { 29 | 30 | while (1) 31 | ; //breakpoint - error detected 32 | } 33 | 34 | } 35 | 36 | if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK) { 37 | 38 | while (1) 39 | ; //breakpoint - error detected 40 | } 41 | 42 | for (var = 0; var < SECTORS_COUNT; var++) { 43 | if (memcmp(buffer_test, 44 | (uint8_t*) (0x90000000 + var * MEMORY_SECTOR_SIZE), 45 | MEMORY_SECTOR_SIZE) != HAL_OK) { 46 | while (1) 47 | ; //breakpoint - error detected - otherwise QSPI works properly 48 | } 49 | } 50 | 51 | /* USER CODE END 2 */ -------------------------------------------------------------------------------- /QSPI testing/testbinary1M.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WellinZHANG/External_Loader/10b35da112eafc26bfe4b0a98fe7eafa11b47b10/QSPI testing/testbinary1M.bin -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # External-Loaders 2 | 3 | This session helps you to integrate QSPI external memory to your Embedded system driven by STM32 4 | 5 | - **Loader_Files** folder contains files needed for STM32 external loader design. 6 | - **QSPI driver** folder contains memory drivers for specific sales types. 7 | - **QSPI testing** folder includes routines for memory testing. 8 | 9 | Video tutorial how to use the files and develop your own external loader is located on website: 10 | 11 | https://www.st.com/content/st_com/en/support/learning/stm32-education/stm32-moocs/external_QSPI_loader.html 12 | 13 | Videos available in MOOC tutorial: 14 | 15 | **1. Intro** 16 | - Includes introduction and prerequisites of tutorial. 17 | 18 | **2. QSPI theory** 19 | - It quickly describes Loader and QSPI functionality. 20 | 21 | **3. CubeMX** 22 | - CubeMX part shows you how to set QSPI peripheral and generate new project from CubeMX tool. 23 | 24 | **4. QSPI Memory driver** 25 | - Each memory command requires specific signal sequence. This part describe how to handle memory commands and create memory driver. 26 | 27 | **5. Test memory driver** 28 | - First part of this video shows how to use and test memory driver in basic application (code located in internal flash). 29 | - Second part changes project properties and generate External loader .stldr file. 30 | --------------------------------------------------------------------------------