├── Post-Build command.txt ├── 4_TouchGFX_mapping ├── Senzanome.png ├── designer1.png ├── designer2.png └── README.md ├── Program_linker_include.txt ├── 3_CubeIDE_mapping └── README.md ├── LICENSE ├── Dev_Inf.h ├── Dev_Inf.c ├── EL_linker.ld ├── 1_Flash_library └── README.md ├── z_flash_W25QXXX.h ├── README.md ├── Loader_Src.c ├── 2_ExternalLoader └── README.md └── z_flash_W25QXXX.c /Post-Build command.txt: -------------------------------------------------------------------------------- 1 | cmd.exe /C copy /Y "${BuildArtifactFileBaseName}.elf" "..\${BuildArtifactFileBaseName}.stldr" -------------------------------------------------------------------------------- /4_TouchGFX_mapping/Senzanome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maudeve-it/W25Qxxx_SPI_FLASH_STM32/HEAD/4_TouchGFX_mapping/Senzanome.png -------------------------------------------------------------------------------- /4_TouchGFX_mapping/designer1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maudeve-it/W25Qxxx_SPI_FLASH_STM32/HEAD/4_TouchGFX_mapping/designer1.png -------------------------------------------------------------------------------- /4_TouchGFX_mapping/designer2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maudeve-it/W25Qxxx_SPI_FLASH_STM32/HEAD/4_TouchGFX_mapping/designer2.png -------------------------------------------------------------------------------- /Program_linker_include.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SPI_FLASH (r) : ORIGIN = 0x90000000, LENGTH = 1M 5 | 6 | 7 | 8 | 9 | 10 | ExtFlashSection : 11 | { 12 | *(ExtFlashSection ExtFlashSection.*) 13 | *(-gnu-linkonce.r.*) 14 | . = ALIGN(0x100); 15 | } >SPI_FLASH 16 | 17 | FontFlashSection : 18 | { 19 | *(FontFlashSection FontFlashSection.*) 20 | *(-gnu-linkonce.r.*) 21 | . = ALIGN(0x100); 22 | } >SPI_FLASH 23 | 24 | 25 | /* attributes for variables declaration */ 26 | /* __attribute__((section("ExtFlashSection"))) __attribute__((aligned(4))) */ -------------------------------------------------------------------------------- /3_CubeIDE_mapping/README.md: -------------------------------------------------------------------------------- 1 | **Piu' sotto, al termine della lingua inglese trovi il testo in italiano. **_ 2 | _**
Below the English text you'll find the Italian version**_ 3 |
4 |
5 |
6 | 7 | 8 | # 3) "How to" setup an STM32CubeIDE project mapping an external flash memory 9 |
STILL UNDER DEVELOPEMENT 10 |
11 |
12 |
13 | 14 | [Back to the home page](../.) 15 | 16 |

17 | 18 |
19 | 20 | --- 21 | 22 |
23 |
24 | 25 | 26 | # "How to" configurare un progetto STM32CubeIDE mappando una memoria flash esterna 27 |
ANCORA IN SVILUPPO 28 |
29 |
30 |
31 | 32 | [Torna alla home page](../.) 33 | 34 |

35 | 36 |
37 | 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Mauro De Vecchi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Dev_Inf.h: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * @file Dev_Inf.h 3 | * @brief modified by Mauro linking W25Qxxx library 4 | * @date: 01 august 2023 5 | * @version V.1.0.0 6 | * 7 | ********************************************* 8 | * you shouldn't need to change anything here 9 | *********************************************/ 10 | 11 | #define MCU_FLASH 1 12 | #define NAND_FLASH 2 13 | #define NOR_FLASH 3 14 | #define SRAM 4 15 | #define PSRAM 5 16 | #define PC_CARD 6 17 | #define SPI_FLASH 7 18 | #define I2C_FLASH 8 19 | #define SDRAM 9 20 | #define I2C_EEPROM 10 21 | 22 | #define SECTOR_NUM 10 // Max Number of Sector types 23 | 24 | struct DeviceSectors 25 | { 26 | unsigned long SectorNum; // Number of Sectors 27 | unsigned long SectorSize; // Sector Size in Bytes 28 | }; 29 | 30 | struct StorageInfo 31 | { 32 | char DeviceName[100]; // Device Name and Description 33 | unsigned short DeviceType; // Device Type: ONCHIP, EXT8BIT, EXT16BIT, ... 34 | unsigned long DeviceStartAddress; // Default Device Start Address 35 | unsigned long DeviceSize; // Total Size of Device 36 | unsigned long PageSize; // Programming Page Size 37 | unsigned char EraseValue; // Content of Erased Memory 38 | struct DeviceSectors sectors[SECTOR_NUM]; 39 | }; 40 | -------------------------------------------------------------------------------- /Dev_Inf.c: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * @file Dev_Inf.c 3 | * @brief modified by Mauro linking W25Qxxx library 4 | * @date: 01 august 2023 5 | * @version V.1.0.0 6 | * 7 | ********************************************* 8 | * Creating an new External loader you have to 9 | * configure the first and the third field in 10 | * below struct. Setup also Loader_Src.c 11 | *********************************************/ 12 | 13 | #include "main.h" 14 | #include "Dev_Inf.h" 15 | #include "z_flash_W25QXXX.h" 16 | 17 | 18 | /* This structure containes information used by ST-LINK Utility to program and erase the device */ 19 | #if defined (__ICCARM__) 20 | __root struct StorageInfo const StorageInfo = { 21 | #else 22 | struct StorageInfo const StorageInfo = { 23 | #endif 24 | "W25Q80_BLACKPILL-F411_LED", // Device Name + version number 25 | SPI_FLASH, // Device Type (that's from Dev_Inf.h) 26 | 0x90000000, // Device Start Address 27 | EXT_FLASH_SIZE, // Device Size in Bytes (that's from Flash interface package) 28 | EXT_FLASH_PAGE_SIZE, // Programming Page Size (that's from Flash interface package) 29 | 0xFF, // Initial Content of Erased Memory 30 | // Specify Size and Address of Sectors (view example below) 31 | EXT_FLASH_PAGE_NUM, EXT_FLASH_SECTOR_SIZE, // (that's from Flash interface package) 32 | 0x00000000, 0x00000000, 33 | }; 34 | 35 | /* Sector coding example 36 | A device with succives 16 Sectors of 1KBytes, 128 Sectors of 16 KBytes, 37 | 8 Sectors of 2KBytes and 16384 Sectors of 8KBytes 38 | 39 | 0x00000010, 0x00000400, // 16 Sectors of 1KBytes 40 | 0x00000080, 0x00004000, // 128 Sectors of 16 KBytes 41 | 0x00000008, 0x00000800, // 8 Sectors of 2KBytes 42 | 0x00004000, 0x00002000, // 16384 Sectors of 8KBytes 43 | 0x00000000, 0x00000000, // end 44 | */ 45 | -------------------------------------------------------------------------------- /EL_linker.ld: -------------------------------------------------------------------------------- 1 | /* 2 | ***************************************************************************** 3 | ** File : linker.ld 4 | ** modified by Mauro linking W25Qxxx library for an EL 5 | ** Date : 01 august 2023 6 | ** Version : V.1.0.0 7 | ** 8 | ** 9 | ** Just change the ram length 10 | ** not tested on H7 11 | ** 12 | ** 13 | ***************************************************************************** 14 | */ 15 | 16 | /* Entry Point */ 17 | ENTRY(Init) 18 | 19 | /* Generate 2 segment for Loader code and device info */ 20 | PHDRS {Loader PT_LOAD ; SgInfo PT_LOAD ; } 21 | 22 | /* Highest address of the user mode stack */ 23 | _estack = ORIGIN(RAM) + LENGTH(RAM); /* end of RAM */ 24 | /* Generate a link error if heap and stack don't fit into RAM */ 25 | _Min_Heap_Size = 0x200; /* required amount of heap */ 26 | _Min_Stack_Size = 0x400; /* required amount of stack */ 27 | 28 | /* Specify the memory areas */ 29 | MEMORY 30 | { 31 | RAM (xrw) : ORIGIN = 0x20000004, LENGTH = 128K 32 | } 33 | 34 | /* Define output sections */ 35 | SECTIONS 36 | { 37 | /* The startup code goes first into FLASH */ 38 | 39 | .isr_vector : 40 | { 41 | . = . + 0x1FC; 42 | . = ALIGN(4); 43 | KEEP(*(.isr_vector)) /* Startup code */ 44 | . = ALIGN(4); 45 | } >RAM :Loader 46 | 47 | 48 | 49 | .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >RAM 50 | .ARM : { 51 | __exidx_start = .; 52 | *(.ARM.exidx*) 53 | __exidx_end = .; 54 | } >RAM :Loader 55 | 56 | .preinit_array : 57 | { 58 | PROVIDE_HIDDEN (__preinit_array_start = .); 59 | KEEP (*(.preinit_array*)) 60 | PROVIDE_HIDDEN (__preinit_array_end = .); 61 | } >RAM :Loader 62 | 63 | .init_array : 64 | { 65 | PROVIDE_HIDDEN (__init_array_start = .); 66 | KEEP (*(SORT(.init_array.*))) 67 | KEEP (*(.init_array*)) 68 | PROVIDE_HIDDEN (__init_array_end = .); 69 | } >RAM :Loader 70 | 71 | .fini_array : 72 | { 73 | PROVIDE_HIDDEN (__fini_array_start = .); 74 | KEEP (*(SORT(.fini_array.*))) 75 | KEEP (*(.fini_array*)) 76 | PROVIDE_HIDDEN (__fini_array_end = .); 77 | } >RAM :Loader 78 | 79 | /* used by the startup to initialize data */ 80 | _sidata = LOADADDR(.data); 81 | 82 | /* Initialized data sections goes into RAM, load LMA copy after code */ 83 | .data : 84 | { 85 | . = ALIGN(4); 86 | _sdata = .; /* create a global symbol at data start */ 87 | *(.data) /* .data sections */ 88 | *(.data*) /* .data* sections */ 89 | 90 | . = ALIGN(4); 91 | _edata = .; /* define a global symbol at data end */ 92 | } >RAM :Loader 93 | 94 | 95 | /* Uninitialized data section */ 96 | . = ALIGN(4); 97 | .bss : 98 | { 99 | /* This is used by the startup in order to initialize the .bss secion */ 100 | _sbss = .; /* define a global symbol at bss start */ 101 | __bss_start__ = _sbss; 102 | *(.bss) 103 | *(.bss*) 104 | *(COMMON) 105 | 106 | . = ALIGN(4); 107 | _ebss = .; /* define a global symbol at bss end */ 108 | __bss_end__ = _ebss; 109 | } >RAM :Loader 110 | 111 | /* The program code and other data goes into FLASH */ 112 | .text : 113 | { 114 | . = ALIGN(4); 115 | *(.text) /* .text sections (code) */ 116 | *(.text*) /* .text* sections (code) */ 117 | /* *(.glue_7) */ /* glue arm to thumb code */ 118 | /* *(.glue_7t) */ /* glue thumb to arm code */ 119 | /* *(.eh_frame) */ 120 | 121 | KEEP (*(.init)) 122 | KEEP (*(.fini)) 123 | 124 | . = ALIGN(4); 125 | _etext = .; /* define a global symbols at end of code */ 126 | } >RAM :Loader 127 | 128 | .Dev_info : 129 | { 130 | KEEP(*Dev_Inf.o ( .rodata* )) 131 | } :SgInfo 132 | 133 | 134 | /* Constant data goes into FLASH */ 135 | .rodata : 136 | { 137 | . = ALIGN(4); 138 | *(.rodata) /* .rodata sections (constants, strings, etc.) */ 139 | *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ 140 | . = ALIGN(4); 141 | } >RAM :Loader 142 | 143 | 144 | /* User_heap_stack section, used to check that there is enough RAM left */ 145 | ._user_heap_stack : 146 | { 147 | . = ALIGN(4); 148 | PROVIDE ( end = . ); 149 | PROVIDE ( _end = . ); 150 | . = . + _Min_Heap_Size; 151 | . = . + _Min_Stack_Size; 152 | . = ALIGN(4); 153 | } >RAM :Loader 154 | 155 | 156 | 157 | 158 | .ARM.attributes 0 : { *(.ARM.attributes) } 159 | } 160 | 161 | 162 | -------------------------------------------------------------------------------- /1_Flash_library/README.md: -------------------------------------------------------------------------------- 1 | **Piu' sotto, al termine della lingua inglese trovi il testo in italiano. **_ 2 | _**
Below the English text you'll find the Italian version**_ 3 |
4 |
5 |
6 | 7 | # 1) Using the W25QXXXX Winbond SPI Flash chip library 8 | Here you'll find documentation about handling a flash memory chip connected to a uC SPI port 9 | 104 | Having done what above shown, you can use all functions of the library handling flash.
105 | Each function has its own description and help, inside z_flash_W25QXXX.c file
106 |
107 |
108 |
109 | 110 | [Back to the home page](../.) 111 | 112 |

113 | 114 |
115 | 116 | ## GitHub Folders 117 | 118 | This guide is divided in 4 chapters following the above list.

119 | 120 | - [handling an external W25Q flash with this library](../1_Flash_library) 121 | - [creating and using an External Loader for the SPI flash](../2_ExternalLoader) 122 | - [mapping an external SPI flash on CubeIDE projects](../3_CubeIDE_mapping) 123 | - [using an external SPI flash in TouchGFX projects](../4_TouchGFX_mapping) 124 | 125 |
126 | 127 | 128 |
129 |
130 | 131 | --- 132 |
133 |
134 |
135 | 136 | 137 | 138 | 139 | # Gestire un chip SPI Flash W25Q di Winbond con questa libreria 140 | Qui trovi le informazioni su come gestire una memoria flash connessa alla porta SPI del uC 141 | 235 | Al termine e' possibile utilizzare le varie funzioni della libreria per gestire la memoria Flash
236 | Le funzioni sono autodescritte e commentate nel file z_flash_W25QXXX.c
237 | 238 |
239 |
240 |
241 | 242 | [Torna alla home page](../.) 243 | 244 |

245 | 246 |
247 | -------------------------------------------------------------------------------- /z_flash_W25QXXX.h: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * @file Z_FLASH_W25QXXX.h 3 | * @author mauro 4 | * @date: 01 august 2023 5 | * @version V.1.0.0 6 | * 7 | ********************************************* 8 | * this version of library uses just polling 9 | * mode transmission 10 | * this version of library uses standard SPI 11 | ********************************************* 12 | * configure below STEP1 and STEP4. 13 | * Do not change STEP2 and STEP3 in this version 14 | *********************************************/ 15 | 16 | #ifndef INC_Z_FLASH_W25QXXX_H_ 17 | #define INC_Z_FLASH_W25QXXX_H_ 18 | 19 | 20 | 21 | /*||||||||||| USER/PROJECT PARAMETERS |||||||||||*/ 22 | 23 | /****************** STEP 1 ****************** 24 | **************** PORT PARAMETERS ***************** 25 | ** properly set the below th 2 defines to address 26 | ******** the SPI port defined on CubeMX ********* 27 | **************************************************/ 28 | #define FLASH_SPI_PORT hspi1 29 | #define FLASH_SPI SPI1 30 | 31 | 32 | /****************** STEP 2 ******************* 33 | **************** FLASH READING MODE *************** 34 | **** FLASH_MODE 1 -> Fast mode 35 | **** FLASH_MODE 2 -> Dual mode // NOT IMPLEMENTED 36 | **** FLASH_MODE 4 -> Quad mode // NOT IMPLEMENTED 37 | **** otherwise -> Standard Mode (warning: standard mode not available if SPO port speed is above 50 MHZ) 38 | **** SPI port must be previously correctly defined via CubeMX 39 | **************************************************/ 40 | #define EXT_FLASH_MODE 1 41 | 42 | 43 | 44 | /***************** STEP 3 ***************** 45 | ************* SPI COMMUNICATION MODE ************** 46 | *** enable SPI mode want, uncommenting ONE row **** 47 | **** (Setup the same configuration on CubeMX) ***** 48 | ***************************************************/ 49 | #define EXT_FLASH_SPI_POLLING_MODE 50 | //#define EXT_FLASH_SPI_DMA_MODE // (mixed: polling/DMA, see below) NOT IMPLEMENTED 51 | 52 | 53 | 54 | /***************** STEP 4 ***************** 55 | *********** set below information as per ************* 56 | ********* chip memory used in the project ********* 57 | ***************************************************/ 58 | /* active information */ 59 | #define EXT_FLASH_PAGE_SIZE 0x0100 //256b page size (bits) 60 | #define EXT_FLASH_SECTOR_SIZE 0x1000 //4kB sector size (bytes) 61 | #define EXT_FLASH_BLOCK_SIZE 0x00010000 //64kB block size (bytes) 62 | #define EXT_FLASH_SIZE 0X00100000 //1MB-8Mb total size (bytes) 63 | #define EXT_FLASH_PAGE_NUM 0x1000 //4096 pages 64 | #define EXT_FLASH_SECTOR_NUM 0x0100 //256 sectors 65 | #define EXT_FLASH_BLOCK_NUM 0x0010 //16 blocks 66 | 67 | 68 | /* here values for the W25Q80DV/DL chips 69 | #define EXT_FLASH_PAGE_SIZE 0x0100 //256b page size (bits) 70 | #define EXT_FLASH_SECTOR_SIZE 0x1000 //4kB sector size (bytes) 71 | #define EXT_FLASH_BLOCK_SIZE 0x00010000 //64kB block size (bytes) 72 | #define EXT_FLASH_SIZE 0X00100000 //1MB-8Mb total size (bytes) 73 | #define EXT_FLASH_PAGE_NUM 0x1000 //4096 pages 74 | #define EXT_FLASH_SECTOR_NUM 0x0100 //256 sectors 75 | #define EXT_FLASH_BLOCK_NUM 0x0010 //16 blocks 76 | */ 77 | 78 | /* here values for the W25Q64JV chips 79 | #define EXT_FLASH_PAGE_SIZE 0x0100 //256b page size (bits) 80 | #define EXT_FLASH_SECTOR_SIZE 0x1000 //4kB sector size (bytes) 81 | #define EXT_FLASH_BLOCK_SIZE 0x00010000 //64kB block size (bytes) 82 | #define EXT_FLASH_SIZE 0X00800000 //8MB-64Mb total size (bytes) 83 | #define EXT_FLASH_PAGE_NUM 0x8000 //32768 pages 84 | #define EXT_FLASH_SECTOR_NUM 0x0800 //2048 sectors 85 | #define EXT_FLASH_BLOCK_NUM 0x0080 //128 blocks 86 | */ 87 | 88 | /* here values for the W25Q128JV chips 89 | #define EXT_FLASH_PAGE_SIZE 0x0100 //256b page size (bits) 90 | #define EXT_FLASH_SECTOR_SIZE 0x1000 //4kB sector size (bytes) 91 | #define EXT_FLASH_BLOCK_SIZE 0x00010000 //64kB block size (bytes) 92 | #define EXT_FLASH_SIZE 0X01000000 //16MB-128Mb total size (bytes) 93 | #define EXT_FLASH_PAGE_NUM 0x00010000 //32768 pages 94 | #define EXT_FLASH_SECTOR_NUM 0x1000 //4096 sectors 95 | #define EXT_FLASH_BLOCK_NUM 0x0100 //256 blocks 96 | */ 97 | 98 | 99 | 100 | 101 | #define EXT_FLASH_DMA_CUTOFF 20 //that's related to uC DMA and SPI. You can leave it unchanged 102 | 103 | /*|||||||| END OF USER/PROJECT PARAMETERS ||||||||*/ 104 | 105 | 106 | 107 | 108 | /*||||||||||||||| DEVICE PARAMETERS ||||||||||||||||||*/ 109 | // W25QXX EEPROM family commands 110 | 111 | #define W25_RESET_EN 0x66 //sequence is 0x66 + 0x99 + 30us delay 112 | #define W25_RESET 0x99 //sequence is 0x66 + 0x99 + 30us delay 113 | #define W25_W_ENABLE 0x06 114 | #define W25_READ 0x03 115 | #define W25_FREAD 0x0B 116 | #define W25_FREAD_DUAL 0x3B 117 | #define W25_FREAD_QUAD 0x6B 118 | #define W25_PAGE_P 0x02 119 | #define W25_S_ERASE4K 0x20 120 | #define W25_B_ERASE32K 0x52 121 | #define W25_B_ERASE64K 0xD8 122 | #define W25_CH_ERASE 0xC7 123 | #define W25_POWERDOWN 0xB9 124 | #define W25_POWERUP_ID 0xAB 125 | #define W25_JEDEC_ID 0x9F 126 | #define W25_R_SR1 0x05 127 | #define W25_R_SFPD_REG 0x5A 128 | 129 | /* unused commands 130 | #define W25_SR_W_ENABLE 0x50 131 | #define W25_W_DISABLE 0x04 132 | #define W25_DEVICE_ID 0x90 133 | #define W25_UNIQUE_ID 0x4B 134 | #define W25_FREAD_DUAL_IO 0xBB 135 | #define W25_FREAD_QUAD_IO 0xEB 136 | #define W25_EP_SUS 0x75 137 | #define W25_EP_RES 0x7A 138 | #define W25_W_SR1 0x01 139 | #define W25_R_SR2 0x35 140 | #define W25_W_SR2 0x31 141 | #define W25_R_SR3 0x15 142 | #define W25_W_SR3 0x11 143 | #define W25_R_SFPD_REG 0x5A 144 | #define W25_E_SEC_REG 0x44 145 | #define W25_P_SEC_REG 0x42 146 | #define W25_R_SEC_REG 0x48 147 | #define W25_G_BL_LOCK 0x7E 148 | #define W25_G_BL_UNLK 0x98 149 | #define W25_R_BL_LOCK 0x3D 150 | #define W25_I_BL_LOCK 0x36 151 | #define W25_I_BL_UNLK 0x39 152 | #define W25_EP_SUSPEND 0x75 153 | #define W25_EP_RESUME 0x75 154 | end of unused commands */ 155 | // W25QXX EEPROM family commands 156 | 157 | #define W25_DUMMY 0x00 //dummy MUST be 0x00, in "read manufacturer" 158 | 159 | // bit masks of W25QXX SR1, SR2, SR3 registers 160 | #define SR1_BIT_BUSY (01U) //status only: 1 means busy device 161 | 162 | /* unused bitmasks 163 | #define SR1_BIT_WEL (02U) //status only: 1 means write enabled. set by W25_W_ENABLE command 164 | #define SR1_BIT_BP0 (04U) //writable: block protect bit 0 165 | #define SR1_BIT_BP1 (08U) //writable: block protect bit 1 166 | #define SR1_BIT_BP2 (10U) //writable: block protect bit 2 167 | #define SR1_BIT_TB (20U) //writable: top(=1)/bottom(=0) starting, block protection bit 168 | #define SR1_BIT_SEC (40U) //writable: sector(4kb)/block(64kb) block protection (1=sector) 169 | #define SR1_BIT_SRP (80U) //writable: set SR registers protection (together with SRL) 170 | #define SR2_BIT_SRL (01U) //writable: set SR registers protection (together with SRL) 171 | #define SR2_BIT_QE (02U) //writable: enable (=1) QUAD SPI mode. if =0 SPI is Standard/Dual 172 | #define SR2_BIT_LB1 (08U) //OTP: 1 means Security Register 1 is permanently set readonly 173 | #define SR2_BIT_LB2 (10U) //OTP: 1 means Security Register 2 is permanently set readonly 174 | #define SR2_BIT_LB3 (20U) //OTP: 1 means Security Register 3 is permanently set readonly 175 | #define SR2_BIT_CMP (40U) //writable: complement protect: reverse protection of BP0-1-2,TB,SEC 176 | #define SR2_BIT_SUS (80U) //writable: suspend status: 1 indicates erase/program suspended 177 | #define SR3_BIT_WPS (04U) //writable: Write protect scheme: 1=using individual block flag, 0=using BPx, etc, flags 178 | #define SR3_BIT_DRV0 (20U) //writable: sets output driver strength 179 | #define SR3_BIT_DRV1 (40U) //writable: sets output driver strength 180 | end of W25QXX SR1, SR2, SR3 registers bitmasks */ 181 | 182 | 183 | #if FLASH_MODE == 1 184 | #define FLASH_READ_COMMAND W25_FREAD 185 | #elif FLASH_MODE == 2 186 | #define FLASH_READ_COMMAND W25_FREAD_DUAL 187 | #elif FLASH_MODE == 4 188 | #define FLASH_READ_COMMAND W25_FREAD_QUAD 189 | #else 190 | #define FLASH_READ_COMMAND W25_READ 191 | #endif 192 | 193 | 194 | 195 | /*||||||||||| END OF DEVICE PARAMETERS ||||||||||||*/ 196 | 197 | 198 | void Flash_Read(uint32_t addr, uint8_t* data, uint32_t dataSize); 199 | void Flash_Write(uint32_t addr, uint8_t* data, uint32_t dataSize); 200 | //void Flash_WaitForWritingComplete(); 201 | void Flash_SErase4k(uint32_t addr); 202 | void Flash_BErase32k(uint32_t addr); 203 | void Flash_BErase64k(uint32_t addr); 204 | void Flash_ChipErase(); 205 | void Flash_PowerDown(); 206 | uint8_t Flash_ReadDevID(); 207 | uint16_t Flash_ReadManufactutrerAndDevID(); 208 | uint32_t Flash_ReadJedecID(); 209 | void Flash_ReadSFDP(uint8_t* data); 210 | void Flash_Reset(); 211 | uint8_t Flash_Init(); //initialization: includes availability test and reset 212 | void DataReader_WaitForReceiveDone(); 213 | void DataReader_ReadData(uint32_t address24, uint8_t* buffer, uint32_t length); 214 | void DataReader_StartDMAReadData(uint32_t address24, uint8_t* buffer, uint32_t length); 215 | 216 | 217 | 218 | 219 | 220 | #endif /* INC_Z_FLASH_W25QXXX_H_ */ 221 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Piu' sotto, al termine della lingua inglese trovi il testo in italiano. **_ 2 | _**
Below the English text you'll find the Italian version**_ 3 |
4 |
5 |
6 | # A W25QXXX SPI FLASH memory library for STM32:
7 | ## including support functions for External Loaders developing
8 | ## and for the flash memory integration on TouchGFX projects
9 |

10 | In this GitHub page, you'll find a library for STM32 (HAL) handling Winbond SPI Flash memories (W25Qxxx).
11 | Library includes functions you need to create External Loaders for STM32CubeProgrammer and STM32CubeIDE.
12 | Inside library you'll find also functions, that TouchGFX needs to handle an external flash memory, reading font and images via a direct transfer flash->display (without needing a cache in RAM).
13 | So, you can use this software for 4 distinct purposes: 14 | 20 |
21 | 22 | --- 23 | 24 |
25 | 26 | ### GitHub Folders 27 | 28 | This guide is divided in 4 chapters following the above list.

29 | 30 | - [handling an external W25Q flash with this library](./1_Flash_library) 31 | - [creating and using an External Loader for the SPI flash](./2_ExternalLoader) 32 | - [mapping an external SPI flash on CubeIDE projects](./3_CubeIDE_mapping) 33 | - [using an external SPI flash in TouchGFX projects](./4_TouchGFX_mapping) 34 | 35 |
36 | 37 | --- 38 | 39 |
40 | 41 | Current version of library handles SPI communication via:
42 | 46 | See youtube videos to know advantages of this approach.


47 | 48 | ### Helping videos 49 | Here you can find video documentation about these topics: 50 | 51 | |||| 52 | |---|---|---| 53 | |Part one| "how to" use library, "how to" develop an EL (specific video for this repository), "how to" install an EL into CubeProgrammer|https://youtu.be/KlG2doCkREM| 54 | |Part two| "how to" create a low-RAM-demanding EL|https://youtu.be/zv0w_vhTTTo| 55 | |Part three| "how to" use the SPI flash in TouchGFX projects, "how to" install an EL into CubeIDE|https://youtu.be/PO_2ZE1NQF0| 56 | |Part four| "how to" map an external SPI flash memory in a CubeIDE project|https://youtu.be/K-7X8WKNu7c| 57 |
58 |
59 | 60 | ### Sources 61 | The sofware you find on this page, the page content and above videos, were developed upon this documentation: 62 | 63 | ||| 64 | |---|---| 65 | |Winbond W25Qxxx web page|https://www.winbond.com/hq/product/code-storage-flash-memory/serial-nor-flash| 66 | |Jedec SFDP standard (requires registration)|https://www.jedec.org/document_search/field_doc_type/148?search_api_views_fulltext=JESD216| 67 | |STM Mooc - External QSPI loader how to|https://www.st.com/content/st_com/en/support/learning/stm32-education/stm32-moocs/external_QSPI_loader.html| 68 | |STM repository of external flash loaders|https://github.com/STMicroelectronics/stm32-external-loader| 69 | |STM32CubeProgrammer documentation|https://www.st.com/resource/en/user_manual/um2237-stm32cubeprogrammer-software-description-stmicroelectronics.pdf| 70 | |STM32 Graphics: external QSPI flash in TouchGFX|https://youtu.be/RMgVo_uCTbw| 71 | |TouchGFX: Using Serial Flash for images and fonts|https://support.touchgfx.com/docs/development/scenarios/using-serial-flash| 72 | 73 |
74 | 75 | 76 | ### Please note 77 | --- 78 | > The software, schemes and PCB designs in this set of repositories are provided just for 79 | > illustrative purposes, sharing the personal experience on this project. 80 | > The software and design artifacts are provided as-is without any mantainence and without 81 | > warranty of any kind. There is no guarantee of fitness for any particular application, 82 | > and no guarantee of completeness and correctness. 83 | > By downloading and using these materials the user accepts all risks associated with the 84 | > run of the software and construction and use of the circuits, boards and devices described.
85 | 86 | --- 87 | 88 | --- 89 | 90 |
91 |
92 |
93 | 94 | # Una libreria sulle memorie SPI Flash W25QXXXX per STM32:
95 | ## incluse le funzioni di supporto per creare External Loader,
96 | ## e per integrare la memoria flash in progetti TouchGFX
97 |

98 | In questa pagina GitHub trovi una libreria di funzioni per STM32 (HAL) per la gestione di memorie SPI Flash Winbond (W25Qxxxx).
99 | La libreria include anche le funzioni richieste per generare External Loader per STM32CubeProgrammer o per STM32CubeIDE.
100 | Nella libreria sono presenti anche le funzioni richeste per integrare una memoria Flash esterna in progetti TouchGFX per memorizzare font ed immagini con trasferimento diretto flash->display (non è richiesta cache in RAM).
101 | Puoi utilizzare quindi questo software per 4 scopi distinti: 102 | 108 |
109 | 110 | --- 111 | 112 |
113 | ### Folder GitHub 114 | 115 | Questa guida è suddivisa in 4 capitoli seguendo lo schema sopra.

116 | - [gestire una memoria flash W25Q attraverso questa libreria](./1_Flash_library) 117 | - [creare and usare an External Loader per le memorie flash SPI](./2_ExternalLoader) 118 | - [mappare una flash SPI esterna sui progetti CubeIDE](./3_CubeIDE_mapping) 119 | - [usare una flash SPI esterna in progetti TouchGFX](./4_TouchGFX_mapping) 120 | 121 |
122 | 123 | --- 124 | 125 |
126 | 127 | La versione attuale della libreria gestisce la comunicazione SPI via:
128 | 132 | Vedi i video youtube sotto per conoscere i vantaggi di questo approccio.


133 | 134 | 135 | ### Supporto video 136 | Qui puoi trovare video relativi ai temi trattati in questa pagina 137 | 138 | |||| 139 | |---|---|---| 140 | |Prima parte|"how to" - come usare la libreria (video specifico per questa repository), come creare un EL, come installare un EL in Cubeprogrammer|https://youtu.be/KlG2doCkREM| 141 | |Seconda parte|"how to" - creare EL a basso consumo di RAM |https://youtu.be/zv0w_vhTTTo| 142 | |Terza parte|"how to" - come usare la memoria FLash SPI in un progetto TouchGFX, come installare un EL in CubeIDE per programmare la memoria flash in un progetto TouchGFX|https://youtu.be/PO_2ZE1NQF0| 143 | |Quarta parte|"how to" - come mappare una memoria flash SPI in un progetto CubeIDE|https://youtu.be/K-7X8WKNu7c| 144 | 145 | ### Referimenti 146 | Il software, questa pagina ed i video sopra sono stati sviluppati sulla base di questa documentazione: 147 | 148 | ||| 149 | |---|---| 150 | |Winbond W25Qxxx web page|https://www.winbond.com/hq/product/code-storage-flash-memory/serial-nor-flash| 151 | |Jedec SFDP standard (requires registration)|https://www.jedec.org/document_search/field_doc_type/148?search_api_views_fulltext=JESD216| 152 | |STM Mooc - External QSPI loader how to|https://www.st.com/content/st_com/en/support/learning/stm32-education/stm32-moocs/external_QSPI_loader.html| 153 | |STM repository of external flash loaders|https://github.com/STMicroelectronics/stm32-external-loader| 154 | |STM32CubeProgrammer documentation|https://www.st.com/resource/en/user_manual/um2237-stm32cubeprogrammer-software-description-stmicroelectronics.pdf| 155 | |STM32 Graphics: external QSPI flash in TouchGFX|https://youtu.be/RMgVo_uCTbw| 156 | |TouchGFX: Using Serial Flash for images and fonts|https://support.touchgfx.com/docs/development/scenarios/using-serial-flash| 157 | 158 | 159 |
160 | 161 | 162 | ### Nota bene 163 | 164 | --- 165 | 166 | > Il software e gli schemi di progetto come i layout PCB in questa serie di repository 167 | > sono messe a disposizione con puro intento illustrativo e di condivisione dell'esperienza fatta. 168 | > Il software e gli elementi del progetto sono messi a disposizione "allo stato in cui sono" 169 | > senza impegno di manutenzione e senza garanzie di alcun tipo. Piu' esplicitamente, non c'e' garanzia di 170 | > adeguatezza a soddisfare specifiche esigenze, ne' di completezza o correttezza di alcuna parte. 171 | > Scaricando ed utilizzando questo materiale l'utilizzatore accetta il rischio associato all'esecuzione del programma e alla 172 | > realizzazione ed all'utilizzo del circuito e dei componenti descritti in questo archivio. 173 | 174 | --- 175 | 176 | 177 | -------------------------------------------------------------------------------- /Loader_Src.c: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * @file Dev_Inf.c 3 | * @brief modified by Mauro linking W25Qxxx library 4 | * @date: 01 august 2023 5 | * @version V.1.0.0 6 | * 7 | ********************************************* 8 | * Creating an new External loader you have to 9 | * follow the below step 1 to 3 and set the 10 | * first field in the struct of Dev_Inf.c 11 | *********************************************/ 12 | 13 | #include "main.h" 14 | #include "spi.h" 15 | #include "gpio.h" 16 | #include "z_flash_W25QXXX.h" 17 | 18 | #define EXT_FLASH_ADDR_MASK 0x0FFFFFFF 19 | 20 | /* STEP 1 ************************************* 21 | * remove comment in below #define if you have 22 | * a led for the External Loader. 23 | * On CubeMX, led's pin label must be LED 24 | * ********************************************/ 25 | #define IS_LED 26 | 27 | /* STEP 2 ************************************* 28 | * change the below #define assigning Pin name 29 | * and port you used for led, 30 | * specify also pin level to turn on led 31 | * ********************************************/ 32 | #ifdef IS_LED 33 | #define LED_PIN_ON GPIO_PIN_RESET //this is the GPIO level turning on led 34 | #endif //IS_LED 35 | 36 | /* STEP 3 ************************************* 37 | * change the init function to call as per SPI 38 | * port used (hint: that's the function 39 | * available in spi.c, check it) 40 | * ********************************************/ 41 | void LOC_SPI_Init(){ 42 | MX_SPI1_Init(); // !!! this line needs to be aligned to the SPI port used! Check this function: it is defined in spi.c !!! 43 | } 44 | 45 | 46 | extern void SystemClock_Config(void); 47 | 48 | /********************************************** 49 | * roughly waints for "Delay" ms before return 50 | * set uC clock speed. Tested on M4, maybe has 51 | * to change using other uC. 52 | * ********************************************/ 53 | void LOC_Delay(uint32_t Delay) { 54 | const uint32_t clock=100; // uC MHz 55 | volatile uint32_t delay1; // 56 | volatile uint32_t multiplier=35; // that's "converting" Delay value into time spent in the below loop 57 | volatile uint32_t k; 58 | delay1=Delay; 59 | for (k=0; (k<(delay1*clock*multiplier)); k++) {}; 60 | } 61 | 62 | 63 | 64 | uint32_t HAL_GetTick(void) { 65 | return 1; 66 | } 67 | 68 | 69 | void HAL_Delay(uint32_t Delay) { 70 | LOC_Delay(Delay); 71 | } 72 | 73 | 74 | HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) { 75 | return HAL_OK; 76 | } 77 | 78 | 79 | 80 | void LOC_LedOn(){ 81 | #ifdef IS_LED 82 | HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, LED_PIN_ON); 83 | #endif //IS_LED 84 | 85 | } 86 | 87 | void LOC_LedOff(){ 88 | #ifdef IS_LED 89 | HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, !LED_PIN_ON); 90 | #endif //IS_LED 91 | } 92 | 93 | 94 | 95 | int Init (void){ 96 | 97 | *(uint32_t*)0xE000EDF0 = 0xA05F0000; //enable interrupts in debug 98 | 99 | SystemInit(); 100 | 101 | /* ADAPTATION TO THE DEVICE 102 | * 103 | * change VTOR setting for H7 device 104 | * SCB->VTOR = 0x24000000 | 0x200; 105 | * 106 | * change VTOR setting for other devices 107 | * SCB->VTOR = 0x20000000 | 0x200; 108 | * 109 | */ 110 | 111 | SCB->VTOR = 0x20000000 | 0x200; 112 | 113 | __set_PRIMASK(0); //enable interrupts 114 | 115 | HAL_Init(); 116 | uint8_t result; 117 | 118 | SystemClock_Config(); 119 | 120 | MX_GPIO_Init(); 121 | LOC_SPI_Init(); 122 | 123 | LOC_LedOn(); 124 | result = Flash_Init(); 125 | LOC_LedOff(); 126 | 127 | __set_PRIMASK(1); //disable interrupts 128 | 129 | return result; 130 | 131 | } 132 | 133 | 134 | 135 | /** 136 | * Description : 137 | * Read data from the device 138 | * Inputs : 139 | * Address : Write location 140 | * Size : Length in bytes 141 | * buffer : Address where to get the data to write 142 | * outputs : 143 | * R0 : "1" : Operation succeeded 144 | * "0" : Operation failure 145 | * Note: Mandatory for all types except SRAM and PSRAM 146 | */ 147 | int Read (uint32_t Address, uint32_t Size, uint8_t* buffer){ 148 | __set_PRIMASK(0); //enable interrupts 149 | Address = Address & EXT_FLASH_ADDR_MASK; 150 | LOC_LedOn(); 151 | Flash_Read(Address, buffer, Size); 152 | LOC_LedOff(); 153 | __set_PRIMASK(1); //disable interrupts 154 | return 1; 155 | } 156 | 157 | 158 | 159 | /** 160 | * Description : 161 | * Write data to the device 162 | * Inputs : 163 | * Address : Write location 164 | * Size : Length in bytes 165 | * buffer : Address where to get the data to write 166 | * outputs : 167 | * R0 : "1" : Operation succeeded 168 | * "0" : Operation failure 169 | * Note: Mandatory for all types except SRAM and PSRAM 170 | */ 171 | int Write (uint32_t Address, uint32_t Size, uint8_t* buffer){ 172 | __set_PRIMASK(0); //enable interrupts 173 | Address = Address & EXT_FLASH_ADDR_MASK; 174 | LOC_LedOn(); 175 | Flash_Write(Address, buffer, Size); 176 | LOC_LedOff(); 177 | __set_PRIMASK(1); //disable interrupts 178 | return 1; 179 | } 180 | 181 | 182 | 183 | 184 | /** 185 | * Description : 186 | * Erase the full chip 187 | * Inputs : 188 | * None 189 | * outputs : 190 | * R0 : "1" : Operation succeeded 191 | * "0" : Operation failure 192 | * Note: Not Mandatory for SRAM PSRAM and NOR_FLASH 193 | */ 194 | int MassErase (void){ 195 | __set_PRIMASK(0); //enable interrupts 196 | LOC_LedOn(); 197 | Flash_ChipErase(); 198 | LOC_LedOff(); 199 | __set_PRIMASK(1); //disable interrupts 200 | return 1; 201 | } 202 | 203 | 204 | 205 | /** 206 | * Description : 207 | * Erase a full sector in the device 208 | * Inputs : 209 | * SectrorAddress : Start of sector 210 | * Size : Size (in WORD) 211 | * InitVal : Initial CRC value 212 | * outputs : 213 | * R0 : "1" : Operation succeeded 214 | * "0" : Operation failure 215 | * Note: Not Mandatory for SRAM PSRAM and NOR_FLASH 216 | */ 217 | int SectorErase (uint32_t EraseStartAddress ,uint32_t EraseEndAddress) { 218 | EraseStartAddress = EraseStartAddress & EXT_FLASH_ADDR_MASK; 219 | EraseEndAddress = EraseEndAddress & EXT_FLASH_ADDR_MASK; 220 | 221 | __set_PRIMASK(0); //enable interrupts 222 | EraseStartAddress = (EraseStartAddress - (EraseStartAddress % EXT_FLASH_BLOCK_SIZE)); 223 | while (EraseEndAddress>=EraseStartAddress) { 224 | LOC_LedOn(); 225 | Flash_BErase64k(EraseStartAddress); 226 | LOC_LedOff(); 227 | EraseStartAddress += EXT_FLASH_BLOCK_SIZE; 228 | } 229 | __set_PRIMASK(1); //disable interrupts 230 | return 1; 231 | } 232 | 233 | 234 | 235 | /** 236 | * Description : 237 | * Calculates checksum value of the memory zone 238 | * Inputs : 239 | * StartAddress : Flash start address 240 | * Size : Size (in WORD) 241 | * InitVal : Initial CRC value 242 | * outputs : 243 | * R0 : Checksum value 244 | * Note - Optional for all types of device 245 | * NOTE - keeping original ST algorithm: not verified and optimized 246 | */ 247 | uint32_t CheckSum(uint32_t StartAddress, uint32_t Size, uint32_t InitVal) { 248 | uint8_t missalignementAddress = StartAddress%4; 249 | uint8_t missalignementSize = Size ; 250 | int cnt; 251 | uint32_t Val; 252 | //uint8_t value; 253 | 254 | StartAddress-=StartAddress%4; 255 | Size += (Size%4==0)?0:4-(Size%4); 256 | 257 | for(cnt=0; cnt>(8*k) & 0xff); 267 | } 268 | missalignementAddress=0; 269 | } 270 | else if((Size-missalignementSize)%4 && (Size-cnt) <=4) 271 | { 272 | for (uint8_t k=(Size-missalignementSize); k<=3;k++){ 273 | InitVal += (uint8_t) (Val>>(8*(k-1)) & 0xff); 274 | } 275 | missalignementSize=2 * missalignementSize - Size; 276 | } 277 | else 278 | { 279 | for (uint8_t k=0; k<=3;k++){ 280 | InitVal += (uint8_t) (Val>>(8*k) & 0xff); 281 | } 282 | } 283 | StartAddress+=4; 284 | } 285 | 286 | return (InitVal); 287 | } 288 | 289 | 290 | /** 291 | * Description : 292 | * Verify flash memory with RAM buffer and calculates checksum value of 293 | * the programmed memory 294 | * Inputs : 295 | * FlashAddr : Flash address 296 | * RAMBufferAddr : RAM buffer address 297 | * Size : Size (in WORD) 298 | * InitVal : Initial CRC value 299 | * outputs : 300 | * R0 : Operation failed (address of failure) 301 | * R1 : Checksum value 302 | * Note: Optional for all types of device 303 | * NOTE - keeping original ST algorithm: not verified and optimized 304 | */ 305 | 306 | uint64_t Verify (uint32_t MemoryAddr, uint32_t RAMBufferAddr, uint32_t Size, uint32_t missalignement){ 307 | #define BUF_SIZE 2 308 | uint32_t InitVal = 0; 309 | uint32_t VerifiedData = 0; 310 | // uint8_t TmpBuffer = 0x00; 311 | uint64_t checksum; 312 | Size*=4; 313 | uint8_t Buffer[BUF_SIZE]; 314 | uint32_t LocAddr = MemoryAddr & EXT_FLASH_ADDR_MASK; 315 | uint32_t posBuf; 316 | 317 | checksum = CheckSum((uint32_t)LocAddr + (missalignement & 0xf), Size - ((missalignement >> 16) & 0xF), InitVal); 318 | 319 | while (Size>VerifiedData) 320 | { 321 | LOC_LedOn(); 322 | Flash_Read(MemoryAddr+VerifiedData, Buffer, BUF_SIZE); 323 | LOC_LedOff(); 324 | 325 | posBuf=0; 326 | while ((Size>VerifiedData) && (posBuf<1024)) { 327 | if (Buffer[posBuf] != *((uint8_t*)RAMBufferAddr+VerifiedData)) 328 | return ((checksum<<32) + MemoryAddr+VerifiedData); 329 | posBuf++; 330 | VerifiedData++; 331 | } 332 | } 333 | 334 | return (checksum<<32); 335 | } 336 | -------------------------------------------------------------------------------- /2_ExternalLoader/README.md: -------------------------------------------------------------------------------- 1 | **Piu' sotto, al termine della lingua inglese trovi il testo in italiano. **_ 2 | _**
Below the English text you'll find the Italian version**_ 3 |
4 |
5 |
6 | 7 | # 2) Creating an EXTERNAL LOADER for STM32CubeProgrammer and STM32CubeIDE 8 | External Loader is a plug-in for STM32CubeProgrammer allowing to read/write an external memory through an STM32 uC.
9 | Through the library shown above it is possible to create an External Loader for an STM32 project having a Winbond external SPI Flash chip .
10 | Next, you will see how you can use the same external loader program in STM32CubeIDE to program external Flash memory directly while creating a project: CubeIDE uses the CubeProgrammer modules to program uC internal and external flash memory. 11 | 12 | ## "How to" create an External Loader for a specific project: 13 | 110 | Now "Compile" the project: If everithing is good you'll find the file project_name.stldr into the project root folder

111 | THIS IS THE EXTERNAL LOADER

112 | 113 | ## "How to" add External Loader to STM32CubeProgrammer 114 | 115 | 125 | 126 | ## "How to" add External Loader to STM32CubeIDE 127 | 145 |
146 |
147 |
148 |
149 |
150 | 151 | [Back to the home page](../.) 152 | 153 |

154 | 155 |
156 | 157 | --- 158 | 159 | --- 160 | 161 |
162 |
163 | 164 | # creare un EXTERNAL LOADER per STM32CubeProgrammer e STM32CubeIDE 165 | External Loader e' un plug-in per STM32CubeProgrammer per leggere e/o programmare un chip di memoria gestito attraverso da un uC STM32.
166 | Attraverso la libreria di funzioni indicata sopra e' possibile creare un external loader per un progetto STM32 che ha una memoria SPI Flash Winbond esterna .
167 | Lo stesso plugin puo' essere utilizzato in STM32CubeIDE per programmare la memoria Flash direttamente durante la creazione di un progetto: CubeIDE usa i moduli CubeProgrammer per programmare la memoria flash interna od esterna del uC. 168 | 169 | ## "How to" come creare an External Loader relativo ad un progetto: 170 | 265 | "Compila" il progetto: se tutto e' andato bene trovi il file "nomeprogetto".stldr nella cartella di root

266 | Questo e' l'external loader

267 | 268 | ## "How to": come aggiungere un External Loader a STM32CubeProgrammer 269 | 279 | 280 | 281 | ## "How to" add External Loader to STM32CubeIDE 282 | 300 |
301 | 302 | [Torna alla home page](../.) 303 | 304 |
305 | 306 |
307 | 308 | -------------------------------------------------------------------------------- /4_TouchGFX_mapping/README.md: -------------------------------------------------------------------------------- 1 | **Piu' sotto, al termine della lingua inglese trovi il testo in italiano. **_ 2 | _**
Below the English text you'll find the Italian version**_ 3 |
4 |
5 |
6 | 7 | # 4) "How to" setup a TouchGFX project mapping an external flash memory 8 | 9 | Setup a TouchGFX project (following https://github.com/maudeve-it/ILI9XXX-XPT2046-STM32)
10 | then:
11 |
  • on CubeMX:
    12 | 33 |
  • on CubeIDE:
    34 | 70 | 154 |
    155 | 156 |
  • on TouchGFX Designer:
    157 |
    158 | 166 | If you move fonts over the external flash memory, you ALWAYS MUST set fonts as "unmapped" in TouchGFX Designer configuration:
    167 |
    168 | 169 |
    170 |
    171 | 172 | --- 173 | > 174 | > WARNING 175 | > 176 | > External SPI flash memory is MUCH slower than uC internal flash.
    177 | > Consider to move to the flash what you really need due to the limit of the uC internal flash 178 | 179 | --- 180 | 181 |
    182 |
  • add the external loader to CubeIDE 183 | 196 |
  • configure CubeIDE to use the external loader
    197 | 206 |
    207 |
    208 | 209 | [Back to the home page](../.) 210 | 211 |

    212 | 213 |
    214 | 215 | --- 216 | 217 | --- 218 | 219 |
    220 |
    221 | 222 | # "How to" come configurare un progetto TouchGFX mappando una memoria flash esterna 223 | Configurare un progetto TouchGFX (segui ad esempio https://github.com/maudeve-it/ILI9XXX-XPT2046-STM32)
    224 | poi:
    225 |
  • in CubeMX:
    226 | 247 |
  • su CubeIDE:
    248 | 283 | Editare lo script per il linker (file ):
    284 |
      285 |
    • aprire lo script per il linker e aprire anche Program_linker_include.txt
      286 |
    • da questo ultimo file copiare la riga che indica la misura e l'indirizzo della memoria flash (inizia con "SPI_FLASH...")
      287 |
    • nello script linker, nell'area "Memories definition", incolla la riga copiata, ottenendo una struttura come questa:
      288 | 289 | ```sh 290 | (xxxxxxFLASH.ld) 291 | ... 292 | /* Memories definition */ 293 | MEMORY 294 | { 295 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K 296 | FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 512K 297 | SPI_FLASH (r) : ORIGIN = 0x90000000, LENGTH = 1M 298 | } 299 | ... 300 | ``` 301 |
      302 | 303 | Non modificare la configurazione RAM, FLASH, o qualunque altra riga si trovi qui: definita e gestita da CubeMX.
      304 | Modificare il campo "LENGTH" di SPI_FLASH indicando la dimensione della memoria flash in uso.
      305 | Il campo "ORIGIN" di SPI_FLASH deve avere lo stesso valore registrato nella configurazione TouchGFX in CubeMX.
      306 | Dal file Program_linker_include.txt copia le righe relative a ExtFlashSection.
      307 | 308 | ```sh 309 | (Program_linker_include.txt) 310 | ... 311 | ExtFlashSection : 312 | { 313 | *(ExtFlashSection ExtFlashSection.*) 314 | *(-gnu-linkonce.r.*) 315 | . = ALIGN(0x100); 316 | } >SPI_FLASH 317 | ... 318 | ``` 319 | 320 | ed incollale all'inizio dell'area SECTIONS dello script linker. In questo modo:
      321 | 322 | ```sh 323 | (xxxxxxFLASH.ld) 324 | ... 325 | 326 | /* Sections */ 327 | SECTIONS 328 | { 329 | ExtFlashSection : 330 | { 331 | *(ExtFlashSection ExtFlashSection.*) 332 | *(-gnu-linkonce.r.*) 333 | . = ALIGN(0x100); 334 | } >SPI_FLASH 335 | ... 336 | ``` 337 |
        338 | questo permette di spostare immagini selezionate verso la memoria flash esterna. 339 | 340 | Volendo/dovendo spostrare anche i fontverso la memoria flash esterna, copia anche la sezione FontFlashSection da Program_linker_include.txt ed incollala nello script linker in questo modo: 341 | 342 | ```sh 343 | (xxxxxxFLASH.ld) 344 | ... 345 | 346 | /* Sections */ 347 | SECTIONS 348 | { 349 | ExtFlashSection : 350 | { 351 | *(ExtFlashSection ExtFlashSection.*) 352 | *(-gnu-linkonce.r.*) 353 | . = ALIGN(0x100); 354 | } >SPI_FLASH 355 | 356 | FontFlashSection : 357 | { 358 | *(FontFlashSection FontFlashSection.*) 359 | *(.gnu.linkonce.r.*) 360 | . = ALIGN(0x4); 361 | } >SPI_FLASH 362 | 363 | ... 364 | ``` 365 |
        366 | 367 |
      • on TouchGFX Designer:
        368 |
        369 |
          370 | A questo punto, in TouchGFX Designer, e' possibile spostare singole immagini verso la memoria flash esterna assegnandole a ExtFlashSection:

          371 | 372 |
          373 |
          Volendo usare la memoria flash esterna come supporto "di default" per archiviare le immagini, impostare il suo valore in Default Image Configuration:
          374 |
          375 |
          376 | 377 |
          378 |
          379 | Se si spostano i font sulla memoria flash esterna OCCORRE SEMPRE impostare i font come "unmapped" in configurazione di TouchGFX Designer:
          380 |
          381 | 382 |
          383 |
        384 | 385 | 386 | 387 | --- 388 | > 389 | > ATTENZIONE 390 | > 391 | > La memoria SPI flash esterna is MOLTO più lenta che la flash interna al uC.
        392 | > Tenere in considerazione di spostare sulla flash esterna solo ciò che occorre veramente a causa dei limiti della flash interna al uC. 393 | 394 | --- 395 | 396 |
        397 |
      • aggiungere l'external loader a CubeIDE 398 |
          399 | andare alla cartella del programma to the STM32CubeIDE 400 | (tasto destro del mouse sull'icona del programma e scegli "Apri percorso file")
          401 | raggiunta la cartella del programma STM32CubeIDEandare in: 402 |
            403 | cartella plugins
            404 | cartella xxxxxx.externaltools.cubeprogrammer.xxxxx
            405 | cartella tools
            406 | cartella bin
            407 | cartella ExternalLoader
            408 |
          409 | copiare qui l'external loader precedentemente creato seguendo following le istruzioni indicate sopra.
          410 |
        411 |
      • Configurare CubeIDE per usare l'external loader:
        412 |
          413 | in CubeIDE andare in: Project->Properties->Run/Debug Settings
          414 | cliccare "Edit"
          415 | selezionare "Debugger"
          416 | sorrere la pagina fino a "External Loaders" e cliccare "Add"
          417 | Selezionare, Nella lista degli external loader, il modulo da usare.
          418 | Cliccare "OK" and "Apply" chidendo la finestra "Properties" aperta. 419 | 420 |
        421 |
        422 |
        423 |
        424 | 425 | [Torna alla home page](../.) 426 | 427 |

        428 | 429 |
        430 | -------------------------------------------------------------------------------- /z_flash_W25QXXX.c: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * @file Z_FLASH_W25QXXX.c 3 | * @author mauro 4 | * @date: 01 august 2023 5 | * @version V.1.0.0 6 | * 7 | ********************************************* 8 | * this version of library uses just polling 9 | * mode transmission 10 | * this version of library uses standard SPI 11 | ********************************************* 12 | * it needs Z_FLASH_W25QXXX.h configuration 13 | *********************************************/ 14 | 15 | 16 | #include "main.h" 17 | #include "z_flash_W25QXXX.h" 18 | 19 | #define SPI_IS_BUSY (HAL_GPIO_ReadPin(FLASH_CS_GPIO_Port, FLASH_CS_Pin)==GPIO_PIN_RESET) 20 | 21 | extern SPI_HandleTypeDef FLASH_SPI_PORT; 22 | 23 | 24 | 25 | 26 | /****************************************** 27 | * @brief enable Flash SPI port 28 | * any command on Flash, any transmission, must start with 29 | * a Chip Select and terminate with a Chip Unselect. 30 | * So testing CS pin let understand if a 31 | * transmission is still running: 32 | * before selecting chip a test over the same CS let 33 | * understand if previous transmission terminated 34 | ******************************************/ 35 | void Flash_Select(void) { 36 | while (SPI_IS_BUSY) {} 37 | HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_RESET); 38 | } 39 | 40 | 41 | 42 | 43 | /****************************************** 44 | * @brief disable Flash SPI 45 | * verifying that there is no a running data transfer 46 | ******************************************/ 47 | void Flash_UnSelect(void) { 48 | // CS pin must be low (selected flash) until previous transmission is completed 49 | #ifdef EXT_FLASH_SPI_POLLING_MODE 50 | HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_SET); //unselect 51 | #endif // FLASH_SPI_POLLING_MODE 52 | } 53 | 54 | 55 | 56 | 57 | void Flash_Receive(uint8_t* data, uint16_t dataSize){ 58 | HAL_SPI_Receive (&FLASH_SPI_PORT , data, dataSize, HAL_MAX_DELAY); 59 | } 60 | 61 | 62 | 63 | /********************************************************************** 64 | * @BRIEF engages SPI port tranferring data to Flash 65 | * just using Polling mode (TouchGFX requires this function) 66 | * @PARAM data buffer data to send 67 | * dataSize number of bytes in "data" to be sent 68 | *********************************************************************/ 69 | void Flash_Polling_Transmit(uint8_t* data, uint16_t dataSize){ 70 | HAL_SPI_Transmit(&FLASH_SPI_PORT , data, dataSize, HAL_MAX_DELAY); 71 | } 72 | 73 | 74 | 75 | 76 | /************************** 77 | * @BRIEF engages SPI port tranferring data to Flash 78 | * Macro parameter DISPL_DMA_CUTOFF defines if transmission is Poling or DMA 79 | * you need to set this macro even using TouchGFX (having its own configuration parameter: 80 | * set DISPL_DMA_CUTOFF and CubeMX parameter to the same value) 81 | * @PARAM data buffer data to send 82 | * dataSize number of bytes in "data" to be sent 83 | **************************/ 84 | void Flash_Transmit(uint8_t* data, uint16_t dataSize){ 85 | #ifndef EXT_FLASH_SPI_POLLING_MODE 86 | if (dataSize> 16) & 0xFF; 136 | buffer[2] = (addr >> 8) & 0xFF; 137 | buffer[3] = addr & 0xFF; 138 | buffer[4] = W25_DUMMY; 139 | Flash_Select(); 140 | Flash_Transmit(buffer, (FLASH_READ_COMMAND == W25_READ ? 4 : 5)); // "normal/slow" read command doesn't need sending dummy byte 141 | 142 | // dataSize is 32 bit, spi_receive handles 16bit transfers, so I have to loop... 143 | while (dataSize) { 144 | data_to_transfer = ((dataSize>0xFFFF) ? 0xFFFF : (uint16_t)dataSize); 145 | Flash_Receive(data, data_to_transfer); 146 | data+=data_to_transfer; 147 | dataSize-=data_to_transfer; 148 | } 149 | Flash_UnSelect(); 150 | } 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | /*********************************************************************** 160 | * @BRIEF it writes into a single FLASH page 161 | * function doesn't check for the BUSY flag in SR1 162 | * function doesn't check for the EEPROM writing enabled 163 | * function doesn't wait for the writing complete 164 | * function doesn't check for the EEPROM page boundary override 165 | * @PARAM addr EEPROM address to start writing 166 | * data buffer containing data to write into EEPROM 167 | * dataSize number of bytes to write 168 | ***********************************************************************/ 169 | void Flash_SimpleWriteAPage(uint32_t addr, uint8_t* data, uint16_t dataSize){ 170 | uint8_t buffer[4]; 171 | buffer[0] = W25_PAGE_P; 172 | buffer[1] = (addr >> 16) & 0xFF; 173 | buffer[2] = (addr >> 8) & 0xFF; 174 | buffer[3] = addr & 0xFF; 175 | Flash_Select(); 176 | Flash_Transmit(buffer, 4); 177 | Flash_Transmit(data, dataSize); 178 | Flash_UnSelect(); 179 | } 180 | 181 | 182 | 183 | 184 | 185 | 186 | /*********************************************************************** 187 | * @BRIEF function writing into EEPROM 188 | * Handling "write enable" commands 189 | * It splits (if needed) received data into the single pages, 190 | * lounching writing sessions for each page 191 | * and waiting the writing complete each time 192 | * @PARAM addr EEPROM address to start writing 193 | * data buffer containing data to write into EEPROM 194 | * dataSize number of bytes to write 195 | ***********************************************************************/ 196 | void Flash_Write(uint32_t addr, uint8_t* data, uint32_t dataSize){ 197 | uint8_t buffer[4]; 198 | uint16_t quota; 199 | uint32_t inpage_addr; 200 | 201 | if (dataSize==0) 202 | return; 203 | 204 | // quota is the data size trasferred until now 205 | quota=0; 206 | 207 | // define the starting write position inside the first Flash page to write... 208 | inpage_addr=addr & (EXT_FLASH_PAGE_SIZE-1); 209 | 210 | // ... so I can detect if more than 1 Flash page has still to be written 211 | while ((dataSize-quota+inpage_addr)>EXT_FLASH_PAGE_SIZE){ 212 | //loop here inside, until more than 1 Flash page... 213 | 214 | Flash_Select(); 215 | buffer[0] = W25_W_ENABLE; 216 | Flash_Transmit(buffer, 1); 217 | Flash_UnSelect(); 218 | Flash_SimpleWriteAPage(addr+quota,data+quota,(EXT_FLASH_PAGE_SIZE-inpage_addr)); 219 | quota+=(EXT_FLASH_PAGE_SIZE-inpage_addr); 220 | // having aligned data to page border on the first writing 221 | // next writings start from 0 position inside a page 222 | inpage_addr=0; 223 | Flash_WaitForWritingComplete(); 224 | } 225 | // now just the final Flash page... 226 | if (dataSize-quota) { 227 | Flash_Select(); 228 | buffer[0] = W25_W_ENABLE; 229 | Flash_Transmit(buffer, 1); 230 | Flash_UnSelect(); 231 | Flash_SimpleWriteAPage(addr+quota,data+quota,dataSize-quota); 232 | Flash_WaitForWritingComplete(); 233 | } 234 | } 235 | 236 | 237 | 238 | 239 | 240 | /********************************** 241 | * @BRIEF Erase to 0XFF all bytes in a 4k block 242 | * 4k block bounary is 0x1000, that means: 243 | * 0x1000, 0x2000, 0x3000, ... 244 | * waiting the writing complete in each page 245 | * @PARAM addr starting erase address 246 | * (it must be a 4k sector boundary) 247 | *********************************/ 248 | void Flash_SErase4k(uint32_t addr){ 249 | uint8_t buffer[4]; 250 | Flash_Select(); 251 | buffer[0] = W25_W_ENABLE; 252 | Flash_Transmit(buffer, 1); 253 | Flash_UnSelect(); 254 | 255 | buffer[0] = W25_S_ERASE4K; 256 | buffer[1] = (addr >> 16) & 0xFF; 257 | buffer[2] = (addr >> 8) & 0xFF; 258 | buffer[3] = addr & 0xFF; 259 | Flash_Select(); 260 | Flash_Transmit(buffer, 4); 261 | Flash_UnSelect(); 262 | Flash_WaitForWritingComplete(); 263 | } 264 | 265 | 266 | 267 | 268 | /********************************** 269 | * @BRIEF Erase to 0XFF all bytes in a 32k block 270 | * 32k block bounary is 0x08000, that means: 271 | * 0x008000, 0x010000, 0x018000, ... 272 | * waiting the writing complete in each page 273 | * @PARAM addr starting erase address 274 | * (it must be a 32k block boundary) 275 | *********************************/ 276 | void Flash_BErase32k(uint32_t addr){ 277 | uint8_t buffer[4]; 278 | Flash_Select(); 279 | buffer[0] = W25_W_ENABLE; 280 | Flash_Transmit(buffer, 1); 281 | Flash_UnSelect(); 282 | 283 | buffer[0] = W25_B_ERASE32K; 284 | buffer[1] = (addr >> 16) & 0xFF; 285 | buffer[2] = (addr >> 8) & 0xFF; 286 | buffer[3] = addr & 0xFF; 287 | Flash_Select(); 288 | Flash_Transmit(buffer, 4); 289 | Flash_UnSelect(); 290 | Flash_WaitForWritingComplete(); 291 | } 292 | 293 | 294 | 295 | 296 | 297 | /********************************** 298 | * @BRIEF Erase to 0XFF all bytes in a 64k block 299 | * 64k block bounary is 0x08000, that means: 300 | * 0x010000, 0x020000, 0x030000, ... 301 | * waiting the writing complete in each page 302 | * @PARAM addr starting erase address 303 | * (it must be a 64k block boundary) 304 | *********************************/ 305 | void Flash_BErase64k(uint32_t addr){ 306 | uint8_t buffer[4]; 307 | Flash_Select(); 308 | buffer[0] = W25_W_ENABLE; 309 | Flash_Transmit(buffer, 1); 310 | Flash_UnSelect(); 311 | 312 | buffer[0] = W25_B_ERASE64K; 313 | buffer[1] = (addr >> 16) & 0xFF; 314 | buffer[2] = (addr >> 8) & 0xFF; 315 | buffer[3] = addr & 0xFF; 316 | Flash_Select(); 317 | Flash_Transmit(buffer, 4); 318 | Flash_UnSelect(); 319 | Flash_WaitForWritingComplete(); 320 | } 321 | 322 | 323 | 324 | 325 | /********************************** 326 | * @BRIEF Full chip erase to 0XFF 327 | * Chip Erase may need up to 100s 328 | * (typ. 20s) 329 | * waiting the writing complete in each page 330 | *********************************/ 331 | void Flash_ChipErase(){ 332 | uint8_t buffer[4]; 333 | Flash_Select(); 334 | buffer[0] = W25_W_ENABLE; 335 | Flash_Transmit(buffer, 1); 336 | Flash_UnSelect(); 337 | 338 | buffer[0] = W25_CH_ERASE; 339 | Flash_Select(); 340 | Flash_Transmit(buffer, 1); 341 | Flash_UnSelect(); 342 | Flash_WaitForWritingComplete(); 343 | } 344 | 345 | 346 | 347 | 348 | 349 | /********************************** 350 | * @BRIEF Initiates a powerdown 351 | * after a powerDown only accepted a porweUp command 352 | * opwerDown operation is 3us long 353 | *********************************/ 354 | void Flash_PowerDown(){ 355 | uint8_t buffer[4]; 356 | 357 | buffer[0] = W25_POWERDOWN; 358 | Flash_Select(); 359 | Flash_Transmit(buffer, 1); 360 | Flash_UnSelect(); 361 | } 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | /********************************** 370 | * @BRIEF Release from powerdown (3 us to restart) or read device ID 371 | *********************************/ 372 | void Flash_PowerUp(){ 373 | uint8_t buffer[4]; 374 | 375 | buffer[0] = W25_POWERUP_ID; 376 | Flash_Select(); 377 | Flash_Transmit(buffer, 1); 378 | Flash_UnSelect(); 379 | HAL_Delay(1); 380 | } 381 | 382 | 383 | 384 | 385 | /********************************** 386 | * @BRIEF read device id from chip 387 | * @RETURN device id 388 | *********************************/ 389 | uint8_t Flash_ReadDevID(){ 390 | uint8_t buffer[4]; 391 | uint8_t data; 392 | 393 | buffer[0] = W25_POWERUP_ID; 394 | buffer[1] = W25_DUMMY; 395 | buffer[2] = W25_DUMMY; 396 | buffer[3] = W25_DUMMY; 397 | Flash_Select(); 398 | Flash_Transmit(buffer, 4); 399 | Flash_Receive(&data, 1); 400 | Flash_UnSelect(); 401 | return data; 402 | } 403 | 404 | 405 | 406 | 407 | 408 | uint16_t Flash_ReadManufactutrerAndDevID() { 409 | uint8_t buffer[4]; 410 | uint16_t data; 411 | 412 | buffer[0] = W25_POWERUP_ID; 413 | buffer[1] = W25_DUMMY; 414 | buffer[2] = W25_DUMMY; 415 | buffer[3] = W25_DUMMY; 416 | Flash_Select(); 417 | Flash_Transmit(buffer, 4); 418 | Flash_Receive((uint8_t*)&data, 2); 419 | Flash_UnSelect(); 420 | return data; 421 | } 422 | 423 | 424 | 425 | 426 | /****************************************************************** 427 | * @RETURN 32bit value divided in 4 bytes: 428 | * (1)MSB dummy 429 | * (2) Jedec Manufacturer ID 430 | * (3) Memory Type 431 | * (4) Capacity 432 | ****************************************************************** 433 | * Memory Capacity code: 434 | * 10H -> 5Mb 11H -> 10Mb 12H -> 20Mb 435 | * 13H -> 40Mb 14H -> 80Mb 15H -> 16Mb 436 | * 16H -> 32Mb 17H -> 64Mb 18H -> 128Mb 437 | * 19H -> 256Mb 20H -> 512Mb 21H -> 1Gb 438 | ******************************************************************/ 439 | uint32_t Flash_ReadJedecID() { 440 | uint8_t buffer[4]; 441 | uint8_t data[3]; 442 | uint32_t result; 443 | 444 | buffer[0] = W25_JEDEC_ID; 445 | Flash_Select(); 446 | Flash_Transmit(buffer, 1); 447 | Flash_Receive(data, 3); 448 | Flash_UnSelect(); 449 | result=((data[0]<<16) | (data[1] <<8) | data[2]); 450 | return result; 451 | } 452 | 453 | 454 | 455 | 456 | /********************************* 457 | * @RETURN 256byte SFDP register content: 458 | *********************************/ 459 | void Flash_ReadSFDP(uint8_t* data) { 460 | uint8_t buffer[5]; 461 | buffer[0] = W25_R_SFPD_REG; 462 | for (uint8_t k=1;k<5;k++) 463 | buffer[k]=0; 464 | Flash_Select(); 465 | Flash_Transmit(buffer, 5); 466 | Flash_Receive(data, 256); 467 | Flash_UnSelect(); 468 | } 469 | 470 | 471 | 472 | 473 | 474 | /********************************* 475 | * @BRIEF testing chip alive and kicking 476 | * reading SFDP record, it must return 477 | * a string beginning with "SFDP" 478 | * @RETURN 1 test passed 479 | * 0 no 480 | *********************************/ 481 | uint8_t Flash_TestAvailability() { 482 | uint8_t data[256]; 483 | uint8_t test=1; 484 | 485 | for (uint8_t k=0;k!=254;k++) 486 | data[k]=0xFF; 487 | Flash_ReadSFDP(data); 488 | if (data[0]!='S') 489 | test=0; 490 | if (data[1]!='F') 491 | test=0; 492 | if (data[2]!='D') 493 | test=0; 494 | if (data[3]!='P') 495 | test=0; 496 | return test; 497 | } 498 | 499 | 500 | 501 | 502 | /****************************************************************** 503 | * @BRIEF reading manufacutrer and device ID 504 | * checking if connected device is a Winbond Flash 505 | ******************************************************************/ 506 | uint8_t Flash_Init(){ 507 | uint32_t JedecID; 508 | HAL_Delay(6); // supposing init is called on system startup: 5 ms (tPUW) required after power-up to be fully available 509 | Flash_Reset(); 510 | if (!Flash_TestAvailability()) 511 | return 0; 512 | JedecID=Flash_ReadJedecID() ; //select the memSize byte 513 | if (((JedecID >> 16) & 0XFF) != 0xEF) // if ManufacturerID is not Winbond (0xEF) 514 | return 0; 515 | return 1; //return memSize as per table in Flash_ReadJedecID() definition 516 | } 517 | 518 | 519 | 520 | 521 | 522 | void Flash_Reset(){ 523 | uint8_t command; 524 | command = W25_RESET_EN; 525 | Flash_Select(); 526 | Flash_Transmit(&command, 1); 527 | Flash_UnSelect(); 528 | command = W25_RESET; 529 | Flash_Select(); 530 | Flash_Transmit(&command, 1); 531 | Flash_UnSelect(); 532 | HAL_Delay(1); // 30us needed by resetting 533 | } 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | void DataReader_WaitForReceiveDone(){ 542 | // nothing to do, being reading always in polling mode 543 | return; 544 | } 545 | 546 | void DataReader_ReadData(uint32_t address24, uint8_t* buffer, uint32_t length){ 547 | Flash_Read(address24, buffer, length); 548 | } 549 | 550 | 551 | void DataReader_StartDMAReadData(uint32_t address24, uint8_t* buffer, uint32_t length){ 552 | //currently using polling mode even if requested DMA 553 | Flash_Read(address24, buffer, length); 554 | } 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | --------------------------------------------------------------------------------