Workshop example
Dependencies: X_NUCLEO_COMMON ST_INTERFACES
QSPIFBlockDevice.h
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2018 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 #ifndef MBED_QSPIF_BLOCK_DEVICE_H 00017 #define MBED_QSPIF_BLOCK_DEVICE_H 00018 00019 #include "QSPI.h" 00020 #include "BlockDevice.h" 00021 00022 /** Enum qspif standard error codes 00023 * 00024 * @enum qspif_bd_error 00025 */ 00026 enum qspif_bd_error { 00027 QSPIF_BD_ERROR_OK = 0, /*!< no error */ 00028 QSPIF_BD_ERROR_DEVICE_ERROR = BD_ERROR_DEVICE_ERROR, /*!< device specific error -4001 */ 00029 QSPIF_BD_ERROR_PARSING_FAILED = -4002, /* SFDP Parsing failed */ 00030 QSPIF_BD_ERROR_READY_FAILED = -4003, /* Wait for Mem Ready failed */ 00031 QSPIF_BD_ERROR_WREN_FAILED = -4004, /* Write Enable Failed */ 00032 QSPIF_BD_ERROR_INVALID_ERASE_PARAMS = -4005, /* Erase command not on sector aligned addresses or exceeds device size */ 00033 QSPIF_BD_ERROR_DEVICE_NOT_UNIQE = -4006, /* Only one instance per csel is allowed */ 00034 QSPIF_BD_ERROR_DEVICE_MAX_EXCEED = -4007 /* Max active QSPIF devices exceeded */ 00035 }; 00036 00037 /** Enum qspif polarity mode 00038 * 00039 * @enum qspif_polarity_mode 00040 */ 00041 enum qspif_polarity_mode { 00042 QSPIF_POLARITY_MODE_0 = 0, /* CPOL=0, CPHA=0 */ 00043 QSPIF_POLARITY_MODE_1 /* CPOL=1, CPHA=1 */ 00044 }; 00045 00046 #define QSPIF_MAX_REGIONS 10 00047 #define MAX_NUM_OF_ERASE_TYPES 4 00048 #define QSPIF_MAX_ACTIVE_FLASH_DEVICES 10 00049 00050 /** BlockDevice for SFDP based flash devices over QSPI bus 00051 * 00052 * @code 00053 * // Here's an example using QSPI flash device on DISCO_L476VG target 00054 * #include "mbed.h" 00055 * #include "QSPIFBlockDevice.h" 00056 * 00057 * QSPIFBlockDevice block_device(QSPI_FLASH1_IO0, QSPI_FLASH1_IO1, QSPI_FLASH1_IO2, QSPI_FLASH1_IO3, 00058 * QSPI_FLASH1_SCK, QSPI_FLASH1_CSN, QSPIF_POLARITY_MODE_0, MBED_CONF_QSPIF_QSPI_FREQ); 00059 * 00060 * int main() 00061 * { 00062 * printf("QSPI SFDP Flash Block Device example\n"); 00063 * 00064 * // Initialize the SPI flash device and print the memory layout 00065 * block_device.init(); 00066 * bd_size_t sector_size_at_address_0 = block_device.get_erase_size(0); 00067 * 00068 * printf("QSPIF BD size: %llu\n", block_device.size()); 00069 * printf("QSPIF BD read size: %llu\n", block_device.get_read_size()); 00070 * printf("QSPIF BD program size: %llu\n", block_device.get_program_size()); 00071 * printf("QSPIF BD erase size (at address 0): %llu\n", sector_size_at_address_0); 00072 * 00073 * // Write "Hello World!" to the first block 00074 * char *buffer = (char *) malloc(sector_size_at_address_0); 00075 * sprintf(buffer, "Hello World!\n"); 00076 * block_device.erase(0, sector_size_at_address_0); 00077 * block_device.program(buffer, 0, sector_size_at_address_0); 00078 * 00079 * // Read back what was stored 00080 * block_device.read(buffer, 0, sector_size_at_address_0); 00081 * printf("%s", buffer); 00082 * 00083 * // Deinitialize the device 00084 * block_device.deinit(); 00085 * } 00086 * @endcode 00087 */ 00088 class QSPIFBlockDevice : public BlockDevice { 00089 public: 00090 /** Create QSPIFBlockDevice - An SFDP based Flash Block Device over QSPI bus 00091 * 00092 * @param io0 1st IO pin used for sending/receiving data during data phase of a transaction 00093 * @param io1 2nd IO pin used for sending/receiving data during data phase of a transaction 00094 * @param io2 3rd IO pin used for sending/receiving data during data phase of a transaction 00095 * @param io3 4th IO pin used for sending/receiving data during data phase of a transaction 00096 * @param sclk QSPI Clock pin 00097 * @param csel QSPI chip select pin 00098 * @param clock_mode specifies the QSPI Clock Polarity mode (QSPIF_POLARITY_MODE_0/QSPIF_POLARITY_MODE_1) 00099 * default value = 0 00100 * @param freq Clock frequency of the QSPI bus (defaults to 40MHz) 00101 * 00102 */ 00103 QSPIFBlockDevice(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName csel, 00104 int clock_mode, int freq = MBED_CONF_QSPIF_QSPI_FREQ); 00105 00106 /** Initialize a block device 00107 * 00108 * @return QSPIF_BD_ERROR_OK(0) - success 00109 * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed 00110 * QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timedout 00111 * QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables 00112 */ 00113 virtual int init(); 00114 00115 /** Deinitialize a block device 00116 * 00117 * @return QSPIF_BD_ERROR_OK(0) - success 00118 * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed 00119 */ 00120 virtual int deinit(); 00121 00122 /** Desctruct QSPIFBlockDevie 00123 */ 00124 ~QSPIFBlockDevice() 00125 { 00126 deinit(); 00127 } 00128 00129 /** Read blocks from a block device 00130 * 00131 * @param buffer Buffer to write blocks to 00132 * @param addr Address of block to begin reading from 00133 * @param size Size to read in bytes, must be a multiple of read block size 00134 * @return QSPIF_BD_ERROR_OK(0) - success 00135 * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed 00136 */ 00137 virtual int read(void *buffer, bd_addr_t addr, bd_size_t size); 00138 00139 /** Program blocks to a block device 00140 * 00141 * The blocks must have been erased prior to being programmed 00142 * 00143 * @param buffer Buffer of data to write to blocks 00144 * @param addr Address of block to begin writing to 00145 * @param size Size to write in bytes, must be a multiple of program block size 00146 * @return QSPIF_BD_ERROR_OK(0) - success 00147 * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed 00148 * QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out 00149 * QSPIF_BD_ERROR_WREN_FAILED - Write Enable failed 00150 * QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables 00151 */ 00152 virtual int program(const void *buffer, bd_addr_t addr, bd_size_t size); 00153 00154 /** Erase blocks on a block device 00155 * 00156 * The state of an erased block is undefined until it has been programmed 00157 * 00158 * @param addr Address of block to begin erasing 00159 * @param size Size to erase in bytes, must be a multiple of erase block size 00160 * @return QSPIF_BD_ERROR_OK(0) - success 00161 * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed 00162 * QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out 00163 * QSPIF_BD_ERROR_WREN_FAILED - Write Enable failed 00164 * QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables 00165 * QSPIF_BD_ERROR_INVALID_ERASE_PARAMS - Trying to erase unaligned address or size 00166 */ 00167 virtual int erase(bd_addr_t addr, bd_size_t size); 00168 00169 /** Get the size of a readable block 00170 * 00171 * @return Size of a readable block in bytes 00172 */ 00173 virtual bd_size_t get_read_size() const; 00174 00175 /** Get the size of a programable block 00176 * 00177 * @return Size of a program block size in bytes 00178 * @note Must be a multiple of the read size 00179 */ 00180 virtual bd_size_t get_program_size() const; 00181 00182 /** Get the size of a eraseable block 00183 * 00184 * @return Size of a minimal erase block, common to all regions, in bytes 00185 * @note Must be a multiple of the program size 00186 */ 00187 virtual bd_size_t get_erase_size() const; 00188 00189 /** Get the size of minimal eraseable sector size of given address 00190 * 00191 * @param addr Any address within block queried for erase sector size (can be any address within flash size offset) 00192 * @return Size of minimal erase sector size, in given address region, in bytes 00193 * @note Must be a multiple of the program size 00194 */ 00195 virtual bd_size_t get_erase_size(bd_addr_t addr); 00196 00197 /** Get the value of storage byte after it was erased 00198 * 00199 * If get_erase_value returns a non-negative byte value, the underlying 00200 * storage is set to that value when erased, and storage containing 00201 * that value can be programmed without another erase. 00202 * 00203 * @return The value of storage when erased, or -1 if you can't 00204 * rely on the value of erased storage 00205 */ 00206 virtual int get_erase_value() const; 00207 00208 /** Get the total size of the underlying device 00209 * 00210 * @return Size of the underlying device in bytes 00211 */ 00212 virtual bd_size_t size() const; 00213 00214 private: 00215 // Internal functions 00216 00217 00218 /********************************/ 00219 /* Different Device Csel Mgmt */ 00220 /********************************/ 00221 // Add a new QSPI device CS to existing devices list. 00222 // Only one QSPIFBlockDevice instance per CS is allowed 00223 int add_new_csel_instance(PinName csel); 00224 00225 // Remove device CS from existing device list upon destroying object (last deinit is called) 00226 int remove_csel_instance(PinName csel); 00227 00228 /********************************/ 00229 /* Calls to QSPI Driver APIs */ 00230 /********************************/ 00231 // Send Program => Write command to Driver 00232 qspi_status_t _qspi_send_program_command(unsigned int prog_instruction, const void *buffer, bd_addr_t addr, 00233 bd_size_t *size); 00234 00235 // Send Read command to Driver 00236 qspi_status_t _qspi_send_read_command(unsigned int read_instruction, void *buffer, bd_addr_t addr, bd_size_t size); 00237 00238 // Send Erase Instruction using command_transfer command to Driver 00239 qspi_status_t _qspi_send_erase_command(unsigned int erase_instruction, bd_addr_t addr, bd_size_t size); 00240 00241 // Send Generic command_transfer command to Driver 00242 qspi_status_t _qspi_send_general_command(unsigned int instruction_int, bd_addr_t addr, const char *tx_buffer, 00243 size_t tx_length, const char *rx_buffer, size_t rx_length); 00244 00245 // Send Bus configure_format command to Driver 00246 qspi_status_t _qspi_configure_format(qspi_bus_width_t inst_width, qspi_bus_width_t address_width, 00247 qspi_address_size_t address_size, qspi_bus_width_t alt_width, qspi_alt_size_t alt_size, qspi_bus_width_t data_width, 00248 int dummy_cycles); 00249 00250 // Send set_frequency command to Driver 00251 qspi_status_t _qspi_set_frequency(int freq); 00252 00253 /*********************************/ 00254 /* Flash Configuration Functions */ 00255 /*********************************/ 00256 // Soft Reset Flash Memory 00257 int _reset_flash_mem(); 00258 00259 // Configure Write Enable in Status Register 00260 int _set_write_enable(); 00261 00262 // Wait on status register until write not-in-progress 00263 bool _is_mem_ready(); 00264 00265 // Enable Fast Mode - for flash chips with low power default 00266 int _enable_fast_mdoe(); 00267 00268 /****************************************/ 00269 /* SFDP Detection and Parsing Functions */ 00270 /****************************************/ 00271 // Parse SFDP Headers and retrieve Basic Param and Sector Map Tables (if exist) 00272 int _sfdp_parse_sfdp_headers(uint32_t &basic_table_addr, size_t &basic_table_size, 00273 uint32_t §or_map_table_addr, size_t §or_map_table_size); 00274 00275 // Parse and Detect required Basic Parameters from Table 00276 int _sfdp_parse_basic_param_table(uint32_t basic_table_addr, size_t basic_table_size); 00277 00278 // Parse and read information required by Regions Secotr Map 00279 int _sfdp_parse_sector_map_table(uint32_t sector_map_table_addr, size_t sector_map_table_size); 00280 00281 // Detect fastest read Bus mode supported by device 00282 int _sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_ptr, int basic_param_table_size, bool &set_quad_enable, 00283 bool &is_qpi_mode, unsigned int &read_inst); 00284 00285 // Enable Quad mode if supported (1-1-4, 1-4-4, 4-4-4 bus modes) 00286 int _sfdp_set_quad_enabled(uint8_t *basic_param_table_ptr); 00287 00288 // Enable QPI mode (4-4-4) is supported 00289 int _sfdp_set_qpi_enabled(uint8_t *basic_param_table_ptr); 00290 00291 // Set Page size for program 00292 int _sfdp_detect_page_size(uint8_t *basic_param_table_ptr, int basic_param_table_size); 00293 00294 // Detect all supported erase types 00295 int _sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size, 00296 unsigned int &erase4k_inst, 00297 unsigned int *erase_type_inst_arr, unsigned int *erase_type_size_arr); 00298 00299 /***********************/ 00300 /* Utilities Functions */ 00301 /***********************/ 00302 // Find the region to which the given offset belong to 00303 int _utils_find_addr_region(bd_size_t offset); 00304 00305 // Iterate on all supported Erase Types of the Region to which the offset belong to. 00306 // Iterates from highest type to lowest 00307 int _utils_iterate_next_largest_erase_type(uint8_t &bitfield, int size, int offset, int boundry); 00308 00309 private: 00310 // Internal Members 00311 00312 // QSPI Driver Object 00313 mbed::QSPI _qspi; 00314 00315 // Static List of different QSPI based Flash devices csel that already exist 00316 // Each QSPI Flash device csel can have only 1 QSPIFBlockDevice instance 00317 // _devices_mutex is used to lock csel list - only one QSPIFBlockDevice instance per csel is allowed 00318 static SingletonPtr<PlatformMutex> _devices_mutex; 00319 static int _number_of_active_qspif_flash_csel; 00320 static PinName *_active_qspif_flash_csel_arr; 00321 00322 int _unique_device_status; 00323 PinName _csel; 00324 00325 // Mutex is used to protect Flash device for some QSPI Driver commands that must be done sequentially with no other commands in between 00326 // e.g. (1)Set Write Enable, (2)Program, (3)Wait Memory Ready 00327 PlatformMutex _mutex; 00328 00329 // Command Instructions 00330 unsigned int _read_instruction; 00331 unsigned int _prog_instruction; 00332 unsigned int _erase_instruction; 00333 unsigned int _erase4k_inst; // Legacy 4K erase instruction (default 0x20h) 00334 unsigned int _write_register_inst; // Write status/config register instruction may vary between chips 00335 unsigned int _read_register_inst; // Read status/config register instruction may vary between chips 00336 00337 // Up To 4 Erase Types are supported by SFDP (each with its own command Instruction and Size) 00338 unsigned int _erase_type_inst_arr[MAX_NUM_OF_ERASE_TYPES]; 00339 unsigned int _erase_type_size_arr[MAX_NUM_OF_ERASE_TYPES]; 00340 00341 // Sector Regions Map 00342 int _regions_count; //number of regions 00343 int _region_size_bytes[QSPIF_MAX_REGIONS]; //regions size in bytes 00344 bd_size_t _region_high_boundary[QSPIF_MAX_REGIONS]; //region high address offset boundary 00345 //Each Region can support a bit combination of any of the 4 Erase Types 00346 uint8_t _region_erase_types_bitfield[QSPIF_MAX_REGIONS]; 00347 unsigned int _min_common_erase_size; // minimal common erase size for all regions (0 if none exists) 00348 00349 unsigned int _page_size_bytes; // Page size - 256 Bytes default 00350 int _freq; 00351 bd_size_t _device_size_bytes; 00352 00353 // Bus speed configuration 00354 qspi_bus_width_t _inst_width; //Bus width for Instruction phase 00355 qspi_bus_width_t _address_width; //Bus width for Address phase 00356 qspi_address_size_t _address_size; // number of bytes for address 00357 qspi_bus_width_t _data_width; //Bus width for Data phase 00358 int _dummy_and_mode_cycles; // Number of Dummy and Mode Bits required by Current Bus Mode 00359 00360 uint32_t _init_ref_count; 00361 bool _is_initialized; 00362 }; 00363 00364 #endif
Generated on Tue Jul 12 2022 22:34:14 by 1.7.2