Mistake on this page?
Report an issue in GitHub or email us
QSPIFBlockDevice.h
1 /* mbed Microcontroller Library
2  * Copyright (c) 2018 ARM Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #ifndef MBED_QSPIF_BLOCK_DEVICE_H
17 #define MBED_QSPIF_BLOCK_DEVICE_H
18 
19 #include "QSPI.h"
20 #include "BlockDevice.h"
21 
22 /** Enum qspif standard error codes
23  *
24  * @enum qspif_bd_error
25  */
26 enum qspif_bd_error {
27  QSPIF_BD_ERROR_OK = 0, /*!< no error */
28  QSPIF_BD_ERROR_DEVICE_ERROR = BD_ERROR_DEVICE_ERROR, /*!< device specific error -4001 */
29  QSPIF_BD_ERROR_PARSING_FAILED = -4002, /* SFDP Parsing failed */
30  QSPIF_BD_ERROR_READY_FAILED = -4003, /* Wait for Mem Ready failed */
31  QSPIF_BD_ERROR_WREN_FAILED = -4004, /* Write Enable Failed */
32  QSPIF_BD_ERROR_INVALID_ERASE_PARAMS = -4005, /* Erase command not on sector aligned addresses or exceeds device size */
33  QSPIF_BD_ERROR_DEVICE_NOT_UNIQE = -4006, /* Only one instance per csel is allowed */
34  QSPIF_BD_ERROR_DEVICE_MAX_EXCEED = -4007 /* Max active QSPIF devices exceeded */
35 };
36 
37 /** Enum qspif polarity mode
38  *
39  * @enum qspif_polarity_mode
40  */
41 enum qspif_polarity_mode {
42  QSPIF_POLARITY_MODE_0 = 0, /* CPOL=0, CPHA=0 */
43  QSPIF_POLARITY_MODE_1 /* CPOL=1, CPHA=1 */
44 };
45 
46 #define QSPIF_MAX_REGIONS 10
47 #define MAX_NUM_OF_ERASE_TYPES 4
48 #define QSPIF_MAX_ACTIVE_FLASH_DEVICES 10
49 
50 /** BlockDevice for SFDP based flash devices over QSPI bus
51  *
52  * @code
53  * // Here's an example using QSPI flash device on DISCO_L476VG target
54  * #include "mbed.h"
55  * #include "QSPIFBlockDevice.h"
56  *
57  * QSPIFBlockDevice block_device(QSPI_FLASH1_IO0, QSPI_FLASH1_IO1, QSPI_FLASH1_IO2, QSPI_FLASH1_IO3,
58  * QSPI_FLASH1_SCK, QSPI_FLASH1_CSN, QSPIF_POLARITY_MODE_0, MBED_CONF_QSPIF_QSPI_FREQ);
59  *
60  * int main()
61  * {
62  * printf("QSPI SFDP Flash Block Device example\n");
63  *
64  * // Initialize the SPI flash device and print the memory layout
65  * block_device.init();
66  * bd_size_t sector_size_at_address_0 = block_device.get_erase_size(0);
67  *
68  * printf("QSPIF BD size: %llu\n", block_device.size());
69  * printf("QSPIF BD read size: %llu\n", block_device.get_read_size());
70  * printf("QSPIF BD program size: %llu\n", block_device.get_program_size());
71  * printf("QSPIF BD erase size (at address 0): %llu\n", sector_size_at_address_0);
72  *
73  * // Write "Hello World!" to the first block
74  * char *buffer = (char *) malloc(sector_size_at_address_0);
75  * sprintf(buffer, "Hello World!\n");
76  * block_device.erase(0, sector_size_at_address_0);
77  * block_device.program(buffer, 0, sector_size_at_address_0);
78  *
79  * // Read back what was stored
80  * block_device.read(buffer, 0, sector_size_at_address_0);
81  * printf("%s", buffer);
82  *
83  * // Deinitialize the device
84  * block_device.deinit();
85  * }
86  * @endcode
87  */
89 public:
90  /** Create QSPIFBlockDevice - An SFDP based Flash Block Device over QSPI bus
91  *
92  * @param io0 1st IO pin used for sending/receiving data during data phase of a transaction
93  * @param io1 2nd IO pin used for sending/receiving data during data phase of a transaction
94  * @param io2 3rd IO pin used for sending/receiving data during data phase of a transaction
95  * @param io3 4th IO pin used for sending/receiving data during data phase of a transaction
96  * @param sclk QSPI Clock pin
97  * @param csel QSPI chip select pin
98  * @param clock_mode specifies the QSPI Clock Polarity mode (QSPIF_POLARITY_MODE_0/QSPIF_POLARITY_MODE_1)
99  * default value = 0
100  * @param freq Clock frequency of the QSPI bus (defaults to 40MHz)
101  *
102  */
103  QSPIFBlockDevice(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName csel,
104  int clock_mode, int freq = MBED_CONF_QSPIF_QSPI_FREQ);
105 
106  /** Initialize a block device
107  *
108  * @return QSPIF_BD_ERROR_OK(0) - success
109  * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
110  * QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timedout
111  * QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
112  */
113  virtual int init();
114 
115  /** Deinitialize a block device
116  *
117  * @return QSPIF_BD_ERROR_OK(0) - success
118  * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
119  */
120  virtual int deinit();
121 
122  /** Desctruct QSPIFBlockDevie
123  */
125  {
126  deinit();
127  }
128 
129  /** Read blocks from a block device
130  *
131  * @param buffer Buffer to write blocks to
132  * @param addr Address of block to begin reading from
133  * @param size Size to read in bytes, must be a multiple of read block size
134  * @return QSPIF_BD_ERROR_OK(0) - success
135  * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
136  */
137  virtual int read(void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
138 
139  /** Program blocks to a block device
140  *
141  * The blocks must have been erased prior to being programmed
142  *
143  * @param buffer Buffer of data to write to blocks
144  * @param addr Address of block to begin writing to
145  * @param size Size to write in bytes, must be a multiple of program block size
146  * @return QSPIF_BD_ERROR_OK(0) - success
147  * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
148  * QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
149  * QSPIF_BD_ERROR_WREN_FAILED - Write Enable failed
150  * QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
151  */
152  virtual int program(const void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
153 
154  /** Erase blocks on a block device
155  *
156  * The state of an erased block is undefined until it has been programmed
157  *
158  * @param addr Address of block to begin erasing
159  * @param size Size to erase in bytes, must be a multiple of erase block size
160  * @return QSPIF_BD_ERROR_OK(0) - success
161  * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
162  * QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
163  * QSPIF_BD_ERROR_WREN_FAILED - Write Enable failed
164  * QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
165  * QSPIF_BD_ERROR_INVALID_ERASE_PARAMS - Trying to erase unaligned address or size
166  */
167  virtual int erase(mbed::bd_addr_t addr, mbed::bd_size_t size);
168 
169  /** Get the size of a readable block
170  *
171  * @return Size of a readable block in bytes
172  */
173  virtual mbed::bd_size_t get_read_size() const;
174 
175  /** Get the size of a programable block
176  *
177  * @return Size of a program block size in bytes
178  * @note Must be a multiple of the read size
179  */
180  virtual mbed::bd_size_t get_program_size() const;
181 
182  /** Get the size of a eraseable block
183  *
184  * @return Size of a minimal erase block, common to all regions, in bytes
185  * @note Must be a multiple of the program size
186  */
187  virtual mbed::bd_size_t get_erase_size() const;
188 
189  /** Get the size of minimal eraseable sector size of given address
190  *
191  * @param addr Any address within block queried for erase sector size (can be any address within flash size offset)
192  * @return Size of minimal erase sector size, in given address region, in bytes
193  * @note Must be a multiple of the program size
194  */
195  virtual mbed::bd_size_t get_erase_size(mbed::bd_addr_t addr);
196 
197  /** Get the value of storage byte after it was erased
198  *
199  * If get_erase_value returns a non-negative byte value, the underlying
200  * storage is set to that value when erased, and storage containing
201  * that value can be programmed without another erase.
202  *
203  * @return The value of storage when erased, or -1 if you can't
204  * rely on the value of erased storage
205  */
206  virtual int get_erase_value() const;
207 
208  /** Get the total size of the underlying device
209  *
210  * @return Size of the underlying device in bytes
211  */
212  virtual mbed::bd_size_t size() const;
213 
214  /** Get the BlockDevice class type.
215  *
216  * @return A string represent the BlockDevice class type.
217  */
218  virtual const char *get_type() const;
219 
220 private:
221  // Internal functions
222 
223 
224  /********************************/
225  /* Different Device Csel Mgmt */
226  /********************************/
227  // Add a new QSPI device CS to existing devices list.
228  // Only one QSPIFBlockDevice instance per CS is allowed
229  int add_new_csel_instance(PinName csel);
230 
231  // Remove device CS from existing device list upon destroying object (last deinit is called)
232  int remove_csel_instance(PinName csel);
233 
234  /********************************/
235  /* Calls to QSPI Driver APIs */
236  /********************************/
237  // Send Program => Write command to Driver
238  qspi_status_t _qspi_send_program_command(unsigned int prog_instruction, const void *buffer, mbed::bd_addr_t addr,
239  mbed::bd_size_t *size);
240 
241  // Send Read command to Driver
242  qspi_status_t _qspi_send_read_command(unsigned int read_instruction, void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
243 
244  // Send Erase Instruction using command_transfer command to Driver
245  qspi_status_t _qspi_send_erase_command(unsigned int erase_instruction, mbed::bd_addr_t addr, mbed::bd_size_t size);
246 
247  // Send Generic command_transfer command to Driver
248  qspi_status_t _qspi_send_general_command(unsigned int instruction_int, mbed::bd_addr_t addr, const char *tx_buffer,
249  size_t tx_length, const char *rx_buffer, size_t rx_length);
250 
251  // Send Bus configure_format command to Driver
252  qspi_status_t _qspi_configure_format(qspi_bus_width_t inst_width, qspi_bus_width_t address_width,
253  qspi_address_size_t address_size, qspi_bus_width_t alt_width, qspi_alt_size_t alt_size, qspi_bus_width_t data_width,
254  int dummy_cycles);
255 
256  // Send set_frequency command to Driver
257  qspi_status_t _qspi_set_frequency(int freq);
258 
259  /*********************************/
260  /* Flash Configuration Functions */
261  /*********************************/
262  // Soft Reset Flash Memory
263  int _reset_flash_mem();
264 
265  // Configure Write Enable in Status Register
266  int _set_write_enable();
267 
268  // Wait on status register until write not-in-progress
269  bool _is_mem_ready();
270 
271  // Enable Fast Mode - for flash chips with low power default
272  int _enable_fast_mdoe();
273 
274  /****************************************/
275  /* SFDP Detection and Parsing Functions */
276  /****************************************/
277  // Parse SFDP Headers and retrieve Basic Param and Sector Map Tables (if exist)
278  int _sfdp_parse_sfdp_headers(uint32_t &basic_table_addr, size_t &basic_table_size,
279  uint32_t &sector_map_table_addr, size_t &sector_map_table_size);
280 
281  // Parse and Detect required Basic Parameters from Table
282  int _sfdp_parse_basic_param_table(uint32_t basic_table_addr, size_t basic_table_size);
283 
284  // Parse and read information required by Regions Secotr Map
285  int _sfdp_parse_sector_map_table(uint32_t sector_map_table_addr, size_t sector_map_table_size);
286 
287  // Detect fastest read Bus mode supported by device
288  int _sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_ptr, int basic_param_table_size, bool &set_quad_enable,
289  bool &is_qpi_mode, unsigned int &read_inst);
290 
291  // Enable Quad mode if supported (1-1-4, 1-4-4, 4-4-4 bus modes)
292  int _sfdp_set_quad_enabled(uint8_t *basic_param_table_ptr);
293 
294  // Enable QPI mode (4-4-4) is supported
295  int _sfdp_set_qpi_enabled(uint8_t *basic_param_table_ptr);
296 
297  // Set Page size for program
298  int _sfdp_detect_page_size(uint8_t *basic_param_table_ptr, int basic_param_table_size);
299 
300  // Detect all supported erase types
301  int _sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size,
302  unsigned int &erase4k_inst,
303  unsigned int *erase_type_inst_arr, unsigned int *erase_type_size_arr);
304 
305  /***********************/
306  /* Utilities Functions */
307  /***********************/
308  // Find the region to which the given offset belong to
309  int _utils_find_addr_region(mbed::bd_size_t offset);
310 
311  // Iterate on all supported Erase Types of the Region to which the offset belong to.
312  // Iterates from highest type to lowest
313  int _utils_iterate_next_largest_erase_type(uint8_t &bitfield, int size, int offset, int boundry);
314 
315 private:
316  // QSPI Driver Object
317  mbed::QSPI _qspi;
318 
319  // Static List of different QSPI based Flash devices csel that already exist
320  // Each QSPI Flash device csel can have only 1 QSPIFBlockDevice instance
321  // _devices_mutex is used to lock csel list - only one QSPIFBlockDevice instance per csel is allowed
322  static SingletonPtr<PlatformMutex> _devices_mutex;
323  static int _number_of_active_qspif_flash_csel;
324  static PinName *_active_qspif_flash_csel_arr;
325 
326  int _unique_device_status;
327  PinName _csel;
328 
329  // Mutex is used to protect Flash device for some QSPI Driver commands that must be done sequentially with no other commands in between
330  // e.g. (1)Set Write Enable, (2)Program, (3)Wait Memory Ready
331  PlatformMutex _mutex;
332 
333  // Command Instructions
334  unsigned int _read_instruction;
335  unsigned int _prog_instruction;
336  unsigned int _erase_instruction;
337  unsigned int _erase4k_inst; // Legacy 4K erase instruction (default 0x20h)
338  unsigned int _write_register_inst; // Write status/config register instruction may vary between chips
339  unsigned int _read_register_inst; // Read status/config register instruction may vary between chips
340 
341  // Up To 4 Erase Types are supported by SFDP (each with its own command Instruction and Size)
342  unsigned int _erase_type_inst_arr[MAX_NUM_OF_ERASE_TYPES];
343  unsigned int _erase_type_size_arr[MAX_NUM_OF_ERASE_TYPES];
344 
345  // Sector Regions Map
346  int _regions_count; //number of regions
347  int _region_size_bytes[QSPIF_MAX_REGIONS]; //regions size in bytes
348  bd_size_t _region_high_boundary[QSPIF_MAX_REGIONS]; //region high address offset boundary
349  //Each Region can support a bit combination of any of the 4 Erase Types
350  uint8_t _region_erase_types_bitfield[QSPIF_MAX_REGIONS];
351  unsigned int _min_common_erase_size; // minimal common erase size for all regions (0 if none exists)
352 
353  unsigned int _page_size_bytes; // Page size - 256 Bytes default
354  int _freq;
355  bd_size_t _device_size_bytes;
356 
357  // Bus speed configuration
358  qspi_bus_width_t _inst_width; //Bus width for Instruction phase
359  qspi_bus_width_t _address_width; //Bus width for Address phase
360  qspi_address_size_t _address_size; // number of bytes for address
361  qspi_bus_width_t _data_width; //Bus width for Data phase
362  int _dummy_and_mode_cycles; // Number of Dummy and Mode Bits required by Current Bus Mode
363 
364  uint32_t _init_ref_count;
365  bool _is_initialized;
366 };
367 
368 #endif
virtual int program(const void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size)
Program blocks to a block device.
virtual mbed::bd_size_t get_program_size() const
Get the size of a programable block.
A hardware device capable of writing and reading blocks.
Definition: BlockDevice.h:47
virtual mbed::bd_size_t get_erase_size() const
Get the size of a eraseable block.
~QSPIFBlockDevice()
Desctruct QSPIFBlockDevie.
virtual int read(void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size)
Read blocks from a block device.
virtual mbed::bd_size_t size() const
Get the total size of the underlying device.
QSPIFBlockDevice(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName csel, int clock_mode, int freq=MBED_CONF_QSPIF_QSPI_FREQ)
Create QSPIFBlockDevice - An SFDP based Flash Block Device over QSPI bus.
enum qspi_alt_size qspi_alt_size_t
Alternative size in bits.
The PlatformMutex class is used to synchronize the execution of threads.
Definition: PlatformMutex.h:47
virtual int get_erase_value() const
Get the value of storage byte after it was erased.
virtual int deinit()
Deinitialize a block device.
virtual mbed::bd_size_t get_read_size() const
Get the size of a readable block.
enum qspi_address_size qspi_address_size_t
Address size in bits.
virtual int erase(mbed::bd_addr_t addr, mbed::bd_size_t size)
Erase blocks on a block device.
virtual int init()
Initialize a block device.
virtual const char * get_type() const
Get the BlockDevice class type.
enum qspi_bus_width qspi_bus_width_t
QSPI Bus width.
BlockDevice for SFDP based flash devices over QSPI bus.
A QSPI Driver, used for communicating with QSPI slave devices.
Definition: QSPI.h:74
enum qspi_status qspi_status_t
QSPI return status.
Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.