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  * SPDX-License-Identifier: Apache-2.0
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #ifndef MBED_QSPIF_BLOCK_DEVICE_H
18 #define MBED_QSPIF_BLOCK_DEVICE_H
19 
20 #include "drivers/QSPI.h"
21 #include "blockdevice/internal/SFDP.h"
22 #include "blockdevice/BlockDevice.h"
23 #include "platform/Callback.h"
24 
25 #ifndef MBED_CONF_QSPIF_QSPI_IO0
26 #define MBED_CONF_QSPIF_QSPI_IO0 NC
27 #endif
28 #ifndef MBED_CONF_QSPIF_QSPI_IO1
29 #define MBED_CONF_QSPIF_QSPI_IO1 NC
30 #endif
31 #ifndef MBED_CONF_QSPIF_QSPI_IO2
32 #define MBED_CONF_QSPIF_QSPI_IO2 NC
33 #endif
34 #ifndef MBED_CONF_QSPIF_QSPI_IO3
35 #define MBED_CONF_QSPIF_QSPI_IO3 NC
36 #endif
37 #ifndef MBED_CONF_QSPIF_QSPI_SCK
38 #define MBED_CONF_QSPIF_QSPI_SCK NC
39 #endif
40 #ifndef MBED_CONF_QSPIF_QSPI_CSN
41 #define MBED_CONF_QSPIF_QSPI_CSN NC
42 #endif
43 #ifndef MBED_CONF_QSPIF_QSPI_POLARITY_MODE
44 #define MBED_CONF_QSPIF_QSPI_POLARITY_MODE 0
45 #endif
46 #ifndef MBED_CONF_QSPIF_QSPI_FREQ
47 #define MBED_CONF_QSPIF_QSPI_FREQ 40000000
48 #endif
49 
50 /** Enum qspif standard error codes
51  *
52  * @enum qspif_bd_error
53  */
54 enum qspif_bd_error {
55  QSPIF_BD_ERROR_OK = 0, /*!< no error */
56  QSPIF_BD_ERROR_DEVICE_ERROR = BD_ERROR_DEVICE_ERROR, /*!< device specific error -4001 */
57  QSPIF_BD_ERROR_PARSING_FAILED = -4002, /* SFDP Parsing failed */
58  QSPIF_BD_ERROR_READY_FAILED = -4003, /* Wait for Mem Ready failed */
59  QSPIF_BD_ERROR_WREN_FAILED = -4004, /* Write Enable Failed */
60  QSPIF_BD_ERROR_INVALID_ERASE_PARAMS = -4005, /* Erase command not on sector aligned addresses or exceeds device size */
61  QSPIF_BD_ERROR_DEVICE_NOT_UNIQUE = -4006, /* Only one instance per csel is allowed */
62  QSPIF_BD_ERROR_DEVICE_MAX_EXCEED = -4007 /* Max active QSPIF devices exceeded */
63 };
64 
65 /** Enum qspif polarity mode
66  *
67  * @enum qspif_polarity_mode
68  */
69 enum qspif_polarity_mode {
70  QSPIF_POLARITY_MODE_0 = 0, /* CPOL=0, CPHA=0 */
71  QSPIF_POLARITY_MODE_1 /* CPOL=1, CPHA=1 */
72 };
73 
74 #define QSPIF_MAX_ACTIVE_FLASH_DEVICES 10
75 
76 /** BlockDevice for SFDP based flash devices over QSPI bus
77  *
78  * @code
79  * // Here's an example using QSPI flash device on DISCO_L476VG target
80  * #include "mbed.h"
81  * #include "QSPIFBlockDevice.h"
82  *
83  * QSPIFBlockDevice block_device(QSPI_FLASH1_IO0, QSPI_FLASH1_IO1, QSPI_FLASH1_IO2, QSPI_FLASH1_IO3,
84  * QSPI_FLASH1_SCK, QSPI_FLASH1_CSN, QSPIF_POLARITY_MODE_0, MBED_CONF_QSPIF_QSPI_FREQ);
85  *
86  * int main()
87  * {
88  * printf("QSPI SFDP Flash Block Device example\n");
89  *
90  * // Initialize the SPI flash device and print the memory layout
91  * block_device.init();
92  * bd_size_t sector_size_at_address_0 = block_device.get_erase_size(0);
93  *
94  * printf("QSPIF BD size: %llu\n", block_device.size());
95  * printf("QSPIF BD read size: %llu\n", block_device.get_read_size());
96  * printf("QSPIF BD program size: %llu\n", block_device.get_program_size());
97  * printf("QSPIF BD erase size (at address 0): %llu\n", sector_size_at_address_0);
98  *
99  * // Write "Hello World!" to the first block
100  * char *buffer = (char *) malloc(sector_size_at_address_0);
101  * sprintf(buffer, "Hello World!\n");
102  * block_device.erase(0, sector_size_at_address_0);
103  * block_device.program(buffer, 0, sector_size_at_address_0);
104  *
105  * // Read back what was stored
106  * block_device.read(buffer, 0, sector_size_at_address_0);
107  * printf("%s", buffer);
108  *
109  * // Deinitialize the device
110  * block_device.deinit();
111  * }
112  * @endcode
113  */
115 public:
116  /** Create QSPIFBlockDevice - An SFDP based Flash Block Device over QSPI bus
117  *
118  * @param io0 1st IO pin used for sending/receiving data during data phase of a transaction
119  * @param io1 2nd IO pin used for sending/receiving data during data phase of a transaction
120  * @param io2 3rd IO pin used for sending/receiving data during data phase of a transaction
121  * @param io3 4th IO pin used for sending/receiving data during data phase of a transaction
122  * @param sclk QSPI Clock pin
123  * @param csel QSPI chip select pin
124  * @param clock_mode specifies the QSPI Clock Polarity mode (QSPIF_POLARITY_MODE_0/QSPIF_POLARITY_MODE_1)
125  * default value = 0
126  * @param freq Clock frequency of the QSPI bus (defaults to 40MHz)
127  */
128  QSPIFBlockDevice(PinName io0 = MBED_CONF_QSPIF_QSPI_IO0,
129  PinName io1 = MBED_CONF_QSPIF_QSPI_IO1,
130  PinName io2 = MBED_CONF_QSPIF_QSPI_IO2,
131  PinName io3 = MBED_CONF_QSPIF_QSPI_IO3,
132  PinName sclk = MBED_CONF_QSPIF_QSPI_SCK,
133  PinName csel = MBED_CONF_QSPIF_QSPI_CSN,
134  int clock_mode = MBED_CONF_QSPIF_QSPI_POLARITY_MODE,
135  int freq = MBED_CONF_QSPIF_QSPI_FREQ);
136 
137  /** Initialize a block device
138  *
139  * @return QSPIF_BD_ERROR_OK(0) - success
140  * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
141  * QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timedout
142  * QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
143  */
144  virtual int init();
145 
146  /** Deinitialize a block device
147  *
148  * @return QSPIF_BD_ERROR_OK(0) - success
149  * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
150  */
151  virtual int deinit();
152 
153  /** Desctruct QSPIFBlockDevie
154  */
156  {
157  deinit();
158  }
159 
160  /** Read blocks from a block device
161  *
162  * @param buffer Buffer to write blocks to
163  * @param addr Address of block to begin reading from
164  * @param size Size to read in bytes, must be a multiple of read block size
165  * @return QSPIF_BD_ERROR_OK(0) - success
166  * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
167  */
168  virtual int read(void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
169 
170  /** Program blocks to a block device
171  *
172  * The blocks must have been erased prior to being programmed
173  *
174  * @param buffer Buffer of data to write to blocks
175  * @param addr Address of block to begin writing to
176  * @param size Size to write in bytes, must be a multiple of program block size
177  * @return QSPIF_BD_ERROR_OK(0) - success
178  * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
179  * QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
180  * QSPIF_BD_ERROR_WREN_FAILED - Write Enable failed
181  * QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
182  */
183  virtual int program(const void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
184 
185  /** Erase blocks on a block device
186  *
187  * The state of an erased block is undefined until it has been programmed
188  *
189  * @param addr Address of block to begin erasing
190  * @param size Size to erase in bytes, must be a multiple of erase block size
191  * @return QSPIF_BD_ERROR_OK(0) - success
192  * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
193  * QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
194  * QSPIF_BD_ERROR_WREN_FAILED - Write Enable failed
195  * QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
196  * QSPIF_BD_ERROR_INVALID_ERASE_PARAMS - Trying to erase unaligned address or size
197  */
198  virtual int erase(mbed::bd_addr_t addr, mbed::bd_size_t size);
199 
200  /** Get the size of a readable block
201  *
202  * @return Size of a readable block in bytes
203  */
204  virtual mbed::bd_size_t get_read_size() const;
205 
206  /** Get the size of a programable block
207  *
208  * @return Size of a program block size in bytes
209  * @note Must be a multiple of the read size
210  */
211  virtual mbed::bd_size_t get_program_size() const;
212 
213  /** Get the size of a eraseable block
214  *
215  * @return Size of a minimal erase block, common to all regions, in bytes
216  * @note Must be a multiple of the program size
217  */
218  virtual mbed::bd_size_t get_erase_size() const;
219 
220  /** Get the size of minimal eraseable sector size of given address
221  *
222  * @param addr Any address within block queried for erase sector size (can be any address within flash size offset)
223  * @return Size of minimal erase sector size, in given address region, in bytes
224  * @note Must be a multiple of the program size
225  */
226  virtual mbed::bd_size_t get_erase_size(mbed::bd_addr_t addr) const;
227 
228  /** Get the value of storage byte after it was erased
229  *
230  * If get_erase_value returns a non-negative byte value, the underlying
231  * storage is set to that value when erased, and storage containing
232  * that value can be programmed without another erase.
233  *
234  * @return The value of storage when erased, or -1 if you can't
235  * rely on the value of erased storage
236  */
237  virtual int get_erase_value() const;
238 
239  /** Get the total size of the underlying device
240  *
241  * @return Size of the underlying device in bytes
242  */
243  virtual mbed::bd_size_t size() const;
244 
245  /** Get the BlockDevice class type.
246  *
247  * @return A string represent the BlockDevice class type.
248  */
249  virtual const char *get_type() const;
250 
251 private:
252  /********************************/
253  /* Different Device Csel Mgmt */
254  /********************************/
255  // Add a new QSPI device CS to existing devices list.
256  // Only one QSPIFBlockDevice instance per CS is allowed
257  int add_new_csel_instance(PinName csel);
258 
259  // Remove device CS from existing device list upon destroying object (last deinit is called)
260  int remove_csel_instance(PinName csel);
261 
262  /********************************/
263  /* Calls to QSPI Driver APIs */
264  /********************************/
265  // Send Program/Write command to Driver
266  qspi_status_t _qspi_send_program_command(mbed::qspi_inst_t prog_instruction, const void *buffer,
267  mbed::bd_addr_t addr, mbed::bd_size_t *size);
268 
269  // Send Read command to Driver
270  qspi_status_t _qspi_send_read_command(mbed::qspi_inst_t read_instruction, void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
271 
272  // Send Erase Instruction using command_transfer command to Driver
273  qspi_status_t _qspi_send_erase_command(mbed::qspi_inst_t erase_instruction, mbed::bd_addr_t addr, mbed::bd_size_t size);
274 
275  // Send Generic command_transfer command to Driver
276  qspi_status_t _qspi_send_general_command(mbed::qspi_inst_t instruction_int, mbed::bd_addr_t addr, const char *tx_buffer,
277  mbed::bd_size_t tx_length, const char *rx_buffer, mbed::bd_size_t rx_length);
278 
279  // Send command to read from the SFDP table
280  int _qspi_send_read_sfdp_command(mbed::bd_addr_t addr, void *rx_buffer, mbed::bd_size_t rx_length);
281 
282  // Read the contents of status registers 1 and 2 into a buffer (buffer must have a length of 2)
283  qspi_status_t _qspi_read_status_registers(uint8_t *reg_buffer);
284 
285  // Set the contents of status registers 1 and 2 from a buffer (buffer must have a length of 2)
286  qspi_status_t _qspi_write_status_registers(uint8_t *reg_buffer);
287 
288  // Send set_frequency command to Driver
289  qspi_status_t _qspi_set_frequency(int freq);
290 
291  // Update the 4-byte addressing extension register with the MSB of the address if it is in use
292  qspi_status_t _qspi_update_4byte_ext_addr_reg(bd_addr_t addr);
293 
294  /*********************************/
295  /* Flash Configuration Functions */
296  /*********************************/
297  // Clear the device's block protection
298  int _clear_block_protection();
299 
300  // Configure Write Enable in Status Register
301  int _set_write_enable();
302 
303  // Wait on status register until write not-in-progress
304  bool _is_mem_ready();
305 
306  // Enable Fast Mode - for flash chips with low power default
307  int _enable_fast_mode();
308 
309  // Query vendor ID and handle special behavior that isn't covered by SFDP data
310  int _handle_vendor_quirks();
311 
312  /****************************************/
313  /* SFDP Detection and Parsing Functions */
314  /****************************************/
315  // Parse and Detect required Basic Parameters from Table
316  int _sfdp_parse_basic_param_table(mbed::Callback<int(mbed::bd_addr_t, void *, mbed::bd_size_t)> sfdp_reader,
317  mbed::sfdp_hdr_info &sfdp_info);
318 
319  // Detect the soft reset protocol and reset - returns error if soft reset is not supported
320  int _sfdp_detect_reset_protocol_and_reset(uint8_t *basic_param_table_ptr);
321 
322  // Detect fastest read Bus mode supported by device
323  int _sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_ptr, int basic_param_table_size,
324  bool &set_quad_enable, bool &is_qpi_mode);
325 
326  // Enable Quad mode if supported (1-1-4, 1-4-4, 4-4-4 bus modes)
327  int _sfdp_set_quad_enabled(uint8_t *basic_param_table_ptr);
328 
329  // Enable QPI mode (4-4-4)
330  int _sfdp_set_qpi_enabled(uint8_t *basic_param_table_ptr);
331 
332  // Detect 4-byte addressing mode and enable it if supported
333  int _sfdp_detect_and_enable_4byte_addressing(uint8_t *basic_param_table_ptr, int basic_param_table_size);
334 
335 private:
336  enum qspif_clear_protection_method_t {
337  QSPIF_BP_ULBPR, // Issue global protection unlock instruction
338  QSPIF_BP_CLEAR_SR, // Clear protection bits in status register 1
339  };
340 
341  // QSPI Driver Object
342  mbed::QSPI _qspi;
343 
344  // Static List of different QSPI based Flash devices csel that already exist
345  // Each QSPI Flash device csel can have only 1 QSPIFBlockDevice instance
346  // _devices_mutex is used to lock csel list - only one QSPIFBlockDevice instance per csel is allowed
347  static SingletonPtr<PlatformMutex> _devices_mutex;
348  static int _number_of_active_qspif_flash_csel;
349  static PinName *_active_qspif_flash_csel_arr;
350 
351  int _unique_device_status;
352  PinName _csel;
353 
354  // Mutex is used to protect Flash device for some QSPI Driver commands that must be done sequentially with no other commands in between
355  // e.g. (1)Set Write Enable, (2)Program, (3)Wait Memory Ready
356  PlatformMutex _mutex;
357 
358  // Command Instructions
359  mbed::qspi_inst_t _read_instruction;
360 
361  // Status register write/read instructions
362  unsigned int _num_status_registers;
363  mbed::qspi_inst_t _write_status_reg_2_inst;
364  mbed::qspi_inst_t _read_status_reg_2_inst; // If three registers, this instruction reads the latter two
365 
366  // Attempt to enable 4-byte addressing. True by default, but may be disabled for some vendors
367  bool _attempt_4_byte_addressing;
368  // 4-byte addressing extension register write instruction
369  mbed::qspi_inst_t _4byte_msb_reg_write_inst;
370 
371  // Quad mode enable status register and bit
372  int _quad_enable_register_idx;
373  int _quad_enable_bit;
374 
375  bool _needs_fast_mode;
376 
377  // Clear block protection
378  qspif_clear_protection_method_t _clear_protection_method;
379 
380  // Data extracted from the devices SFDP structure
381  mbed::sfdp_hdr_info _sfdp_info;
382 
383  unsigned int _page_size_bytes; // Page size - 256 Bytes default
384  int _freq;
385 
386  // Bus speed configuration
387  qspi_bus_width_t _inst_width; //Bus width for Instruction phase
388  qspi_bus_width_t _address_width; //Bus width for Address phase
389  qspi_address_size_t _address_size; //Number of bits for address
390  qspi_alt_size_t _alt_size; //Number of bits for alt
391  bool _alt_enabled; //Whether alt is enabled
392  uint8_t _dummy_cycles; //Number of Dummy cycles required by Current Bus Mode
393  qspi_bus_width_t _data_width; //Bus width for Data phase
394 
395  uint32_t _init_ref_count;
396  bool _is_initialized;
397 };
398 
399 #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.
QSPIFBlockDevice(PinName io0=NC, PinName io1=NC, PinName io2=NC, PinName io3=NC, PinName sclk=NC, PinName csel=NC, int clock_mode=0, int freq=40000000)
Create QSPIFBlockDevice - An SFDP based Flash Block Device over QSPI bus.
A hardware device capable of writing and reading blocks.
Definition: BlockDevice.h:48
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.
The PlatformMutex class is used to synchronize the execution of threads.
Definition: PlatformMutex.h:47
SFDP JEDEC Parameter Table info.
Definition: SFDP.h:79
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.
int qspi_inst_t
Type representing a QSPI instruction.
Definition: QSPI.h:46
virtual const char * get_type() const
Get the BlockDevice class type.
uint8_t qspi_alt_size_t
Alternative size in bits.
Definition: qspi_api.h:79
enum qspi_bus_width qspi_bus_width_t
QSPI Bus width.
BlockDevice for SFDP based flash devices over QSPI bus.
Callback class based on template specialization.
Definition: Callback.h:53
A QSPI Driver, used for communicating with QSPI slave devices.
Definition: QSPI.h:86
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.