Mistake on this page?
Report an issue in GitHub or email us
SPINANDBlockDevice.h
1 /* mbed Microcontroller Library
2  * Copyright (c) 2021 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_SPINAND_BLOCK_DEVICE_H
18 #define MBED_SPINAND_BLOCK_DEVICE_H
19 
20 #include "drivers/QSPI.h"
21 #include "blockdevice/BlockDevice.h"
22 #include "platform/Callback.h"
23 
24 #ifndef MBED_CONF_SPINAND_QSPI_IO0
25 #define MBED_CONF_SPINAND_QSPI_IO0 NC
26 #endif
27 #ifndef MBED_CONF_SPINAND_QSPI_IO1
28 #define MBED_CONF_SPINAND_QSPI_IO1 NC
29 #endif
30 #ifndef MBED_CONF_SPINAND_QSPI_IO2
31 #define MBED_CONF_SPINAND_QSPI_IO2 NC
32 #endif
33 #ifndef MBED_CONF_SPINAND_QSPI_IO3
34 #define MBED_CONF_SPINAND_QSPI_IO3 NC
35 #endif
36 #ifndef MBED_CONF_SPINAND_QSPI_SCK
37 #define MBED_CONF_SPINAND_QSPI_SCK NC
38 #endif
39 #ifndef MBED_CONF_SPINAND_QSPI_CSN
40 #define MBED_CONF_SPINAND_QSPI_CSN NC
41 #endif
42 #ifndef MBED_CONF_SPINAND_QSPI_POLARITY_MODE
43 #define MBED_CONF_SPINAND_QSPI_POLARITY_MODE 0
44 #endif
45 #ifndef MBED_CONF_SPINAND_QSPI_FREQ
46 #define MBED_CONF_SPINAND_QSPI_FREQ 40000000
47 #endif
48 
49 /** Enum spinand standard error codes
50  *
51  * @enum spinand_bd_error
52  */
53 enum spinand_bd_error {
54  SPINAND_BD_ERROR_OK = 0, /*!< no error */
55  SPINAND_BD_ERROR_DEVICE_ERROR = BD_ERROR_DEVICE_ERROR, /*!< device specific error -4001 */
56  SPINAND_BD_ERROR_PARSING_FAILED = -4002, /* SFDP Parsing failed */
57  SPINAND_BD_ERROR_READY_FAILED = -4003, /* Wait for Mem Ready failed */
58  SPINAND_BD_ERROR_WREN_FAILED = -4004, /* Write Enable Failed */
59  SPINAND_BD_ERROR_INVALID_ERASE_PARAMS = -4005, /* Erase command not on sector aligned addresses or exceeds device size */
60  SPINAND_BD_ERROR_DEVICE_NOT_UNIQUE = -4006, /* Only one instance per csel is allowed */
61  SPINAND_BD_ERROR_DEVICE_MAX_EXCEED = -4007 /* Max active SPINAND devices exceeded */
62 };
63 
64 /** Enum spinand polarity mode
65  *
66  * @enum spinand_polarity_mode
67  */
68 enum spinand_polarity_mode {
69  SPINAND_POLARITY_MODE_0 = 0, /* CPOL=0, CPHA=0 */
70  SPINAND_POLARITY_MODE_1 /* CPOL=1, CPHA=1 */
71 };
72 
73 #define SPINAND_MAX_ACTIVE_FLASH_DEVICES 10
74 
75 /** BlockDevice for SPI NAND flash devices over QSPI bus
76  *
77  * @code
78  * // Here's an example using SPI NAND flash device on DISCO_L4R9I target
79  * #include "mbed.h"
80  * #include "SPINANDBlockDevice.h"
81  *
82  * SPINANDBlockDevice block_device(SPINAND_FLASH1_IO0, SPINAND_FLASH1_IO1, SPINAND_FLASH1_IO2, SPINAND_FLASH1_IO3,
83  * SPINAND_FLASH1_SCK, SPINAND_FLASH1_CSN, SPINAND_POLARITY_MODE_0, MBED_CONF_SPINAND_QSPI_FREQ);
84  *
85  * int main()
86  * {
87  * printf("SPI NAND Flash Block Device example\n");
88  *
89  * // Initialize the SPI NAND flash device and print the memory layout
90  * block_device.init();
91  * bd_size_t sector_size_at_address_0 = block_device.get_erase_size(0);
92  *
93  * printf("SPINAND BD size: %llu\n", block_device.size());
94  * printf("SPINAND BD read size: %llu\n", block_device.get_read_size());
95  * printf("SPINAND BD program size: %llu\n", block_device.get_program_size());
96  * printf("SPINAND BD erase size (at address 0): %llu\n", sector_size_at_address_0);
97  *
98  * // Write "Hello World!" to the first block
99  * char *buffer = (char *) malloc(sector_size_at_address_0);
100  * sprintf(buffer, "Hello World!\n");
101  * block_device.erase(0, sector_size_at_address_0);
102  * block_device.program(buffer, 0, sector_size_at_address_0);
103  *
104  * // Read back what was stored
105  * block_device.read(buffer, 0, sector_size_at_address_0);
106  * printf("%s", buffer);
107  *
108  * // Deinitialize the device
109  * block_device.deinit();
110  * }
111  * @endcode
112  */
114 public:
115  /** Create SPINANDBlockDevice - An SPI NAND Flash Block Device over QSPI bus
116  *
117  * @param io0 1st IO pin used for sending/receiving data during data phase of a transaction
118  * @param io1 2nd IO pin used for sending/receiving data during data phase of a transaction
119  * @param io2 3rd IO pin used for sending/receiving data during data phase of a transaction
120  * @param io3 4th IO pin used for sending/receiving data during data phase of a transaction
121  * @param sclk QSPI Clock pin
122  * @param csel QSPI chip select pin
123  * @param clock_mode specifies the QSPI Clock Polarity mode (SPINAND_POLARITY_MODE_0/SPINAND_POLARITY_MODE_1)
124  * default value = 0
125  * @param freq Clock frequency of the QSPI bus (defaults to 40MHz)
126  */
127  SPINANDBlockDevice(PinName io0 = MBED_CONF_SPINAND_QSPI_IO0,
128  PinName io1 = MBED_CONF_SPINAND_QSPI_IO1,
129  PinName io2 = MBED_CONF_SPINAND_QSPI_IO2,
130  PinName io3 = MBED_CONF_SPINAND_QSPI_IO3,
131  PinName sclk = MBED_CONF_SPINAND_QSPI_SCK,
132  PinName csel = MBED_CONF_SPINAND_QSPI_CSN,
133  int clock_mode = MBED_CONF_SPINAND_QSPI_POLARITY_MODE,
134  int freq = MBED_CONF_SPINAND_QSPI_FREQ);
135 
136  /** Initialize a block device
137  *
138  * @return SPINAND_BD_ERROR_OK(0) - success
139  * SPINAND_BD_ERROR_DEVICE_ERROR - device driver transaction failed
140  * SPINAND_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timedout
141  */
142  virtual int init();
143 
144  /** Deinitialize a block device
145  *
146  * @return SPINAND_BD_ERROR_OK(0) - success
147  * SPINAND_BD_ERROR_DEVICE_ERROR - device driver transaction failed
148  */
149  virtual int deinit();
150 
151  /** Destruct SPINANDBlockDevie
152  */
154  {
155  deinit();
156  }
157 
158  /** Read blocks from a block device
159  *
160  * @param buffer Buffer to write blocks to
161  * @param addr Address of block to begin reading from
162  * @param size Size to read in bytes, must be a multiple of read block size
163  * @return SPINAND_BD_ERROR_OK(0) - success
164  * SPINAND_BD_ERROR_DEVICE_ERROR - device driver transaction failed
165  */
166  virtual int read(void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
167 
168  /** Program blocks to a block device
169  *
170  * The blocks must have been erased prior to being programmed
171  *
172  * @param buffer Buffer of data to write to blocks
173  * @param addr Address of block to begin writing to
174  * @param size Size to write in bytes, must be a multiple of program block size
175  * @return SPINAND_BD_ERROR_OK(0) - success
176  * SPINAND_BD_ERROR_DEVICE_ERROR - device driver transaction failed
177  * SPINAND_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
178  * SPINAND_BD_ERROR_WREN_FAILED - Write Enable failed
179  */
180  virtual int program(const void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
181 
182  /** Erase blocks on a block device
183  *
184  * The state of an erased block is undefined until it has been programmed
185  *
186  * @param addr Address of block to begin erasing
187  * @param size Size to erase in bytes, must be a multiple of erase block size
188  * @return SPINAND_BD_ERROR_OK(0) - success
189  * SPINAND_BD_ERROR_DEVICE_ERROR - device driver transaction failed
190  * SPINAND_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
191  * SPINAND_BD_ERROR_WREN_FAILED - Write Enable failed
192  * SPINAND_BD_ERROR_INVALID_ERASE_PARAMS - Trying to erase unaligned address or size
193  */
194  virtual int erase(mbed::bd_addr_t addr, mbed::bd_size_t size);
195 
196  /** Get the size of a readable block
197  *
198  * @return Size of a readable block in bytes
199  */
200  virtual mbed::bd_size_t get_read_size() const;
201 
202  /** Get the size of a programable block
203  *
204  * @return Size of a program block size in bytes
205  * @note Must be a multiple of the read size
206  */
207  virtual mbed::bd_size_t get_program_size() const;
208 
209  /** Get the size of a eraseable block
210  *
211  * @return Size of a minimal erase block, common to all regions, in bytes
212  * @note Must be a multiple of the program size
213  */
214  virtual mbed::bd_size_t get_erase_size() const;
215  virtual mbed::bd_size_t get_erase_size(bd_addr_t addr) const;
216 
217  /** Get the value of storage byte after it was erased
218  *
219  * If get_erase_value returns a non-negative byte value, the underlying
220  * storage is set to that value when erased, and storage containing
221  * that value can be programmed without another erase.
222  *
223  * @return The value of storage when erased, or -1 if you can't
224  * rely on the value of erased storage
225  */
226  virtual int get_erase_value() const;
227 
228  /** Get the total size of the underlying device
229  *
230  * @return Size of the underlying device in bytes
231  */
232  virtual mbed::bd_size_t size() const;
233 
234  /** Get the BlockDevice class type.
235  *
236  * @return A string represent the BlockDevice class type.
237  */
238  virtual const char *get_type() const;
239 
240 private:
241  /********************************/
242  /* Different Device Csel Mgmt */
243  /********************************/
244  // Add a new SPI NAND device CS to existing devices list.
245  // Only one SPINANDBlockDevice instance per CS is allowed
246  int add_new_csel_instance(PinName csel);
247 
248  // Remove device CS from existing device list upon destroying object (last deinit is called)
249  int remove_csel_instance(PinName csel);
250 
251  /********************************/
252  /* Calls to QSPI Driver APIs */
253  /********************************/
254  // Send Program/Write command to Driver
255  qspi_status_t _qspi_send_program_command(mbed::qspi_inst_t prog_instruction, const void *buffer,
256  mbed::bd_addr_t addr, mbed::bd_size_t *size);
257 
258  // Send Read command to Driver
259  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);
260 
261  // Send Erase Instruction using command_transfer command to Driver
262  qspi_status_t _qspi_send_erase_command(mbed::qspi_inst_t erase_instruction, mbed::bd_addr_t addr, mbed::bd_size_t size);
263 
264  // Send Generic command_transfer command to Driver
265  qspi_status_t _qspi_send_general_command(mbed::qspi_inst_t instruction_int, mbed::bd_addr_t addr, const char *tx_buffer,
266  mbed::bd_size_t tx_length, const char *rx_buffer, mbed::bd_size_t rx_length);
267 
268  // Send set_frequency command to Driver
269  qspi_status_t _qspi_set_frequency(int freq);
270 
271  /*********************************/
272  /* Flash Configuration Functions */
273  /*********************************/
274 
275  // Quad Enable in Security Register
276  int _set_quad_enable();
277 
278  // Clear the device's block protection
279  int _clear_block_protection();
280 
281  // Configure Write Enable in Status Register
282  int _set_write_enable();
283 
284  // Wait on status register until write not-in-progress
285  bool _is_mem_ready();
286 
287 private:
288 
289  // QSPI Driver Object
290  mbed::QSPI _qspi;
291 
292  // Static List of different QSPI based Flash devices csel that already exist
293  // Each QSPI Flash device csel can have only 1 SPINANDBlockDevice instance
294  // _devices_mutex is used to lock csel list - only one SPINANDBlockDevice instance per csel is allowed
295  static SingletonPtr<PlatformMutex> _devices_mutex;
296  static int _number_of_active_spinand_flash_csel;
297  static PinName *_active_spinand_flash_csel_arr;
298 
299  int _unique_device_status;
300  PinName _csel;
301 
302  // Mutex is used to protect Flash device for some QSPI Driver commands that must be done sequentially with no other commands in between
303  // e.g. (1)Set Write Enable, (2)Program, (3)Wait Memory Ready
304  PlatformMutex _mutex;
305 
306  // Command Instructions
307  mbed::qspi_inst_t _read_instruction;
308  mbed::qspi_inst_t _program_instruction;
309 
310  int _freq;
311 
312  // Bus speed configuration
313  qspi_bus_width_t _inst_width; //Bus width for Instruction phase
314  qspi_bus_width_t _address_width; //Bus width for Address phase
315  qspi_address_size_t _address_size; //Number of bits for address
316  qspi_alt_size_t _alt_size; //Number of bits for alt
317  bool _alt_enabled; //Whether alt is enabled
318  uint8_t _dummy_cycles; //Number of Dummy cycles required by Current Bus Mode
319  qspi_bus_width_t _data_width; //Bus width for Data phase
320 
321  uint32_t _init_ref_count;
322  bool _is_initialized;
323 };
324 
325 #endif
virtual int get_erase_value() const
Get the value of storage byte after it was erased.
~SPINANDBlockDevice()
Destruct SPINANDBlockDevie.
virtual mbed::bd_size_t size() const
Get the total size of the underlying device.
virtual const char * get_type() const
Get the BlockDevice class type.
virtual int erase(mbed::bd_addr_t addr, mbed::bd_size_t size)
Erase blocks on a block device.
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.
BlockDevice for SPI NAND flash devices over QSPI bus.
SPINANDBlockDevice(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 SPINANDBlockDevice - An SPI NAND Flash Block Device over QSPI bus.
The PlatformMutex class is used to synchronize the execution of threads.
Definition: PlatformMutex.h:47
virtual int init()
Initialize a block device.
virtual int deinit()
Deinitialize a block device.
virtual mbed::bd_size_t get_read_size() const
Get the size of a readable block.
virtual int read(void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size)
Read blocks from a block device.
enum qspi_address_size qspi_address_size_t
Address size in bits.
int qspi_inst_t
Type representing a QSPI instruction.
Definition: QSPI.h:46
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.
virtual int program(const void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size)
Program blocks to a block device.
A QSPI Driver, used for communicating with QSPI slave devices.
Definition: QSPI.h:86
virtual mbed::bd_size_t get_program_size() const
Get the size of a programable block.
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.