Mistake on this page?
Report an issue in GitHub or email us
SPIFBlockDevice.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_SPIF_BLOCK_DEVICE_H
17 #define MBED_SPIF_BLOCK_DEVICE_H
18 
19 #include "platform/SingletonPtr.h"
20 #include "drivers/SPI.h"
21 #include "drivers/DigitalOut.h"
22 #include "features/storage/blockdevice/BlockDevice.h"
23 
24 /** Enum spif standard error codes
25  *
26  * @enum spif_bd_error
27  */
28 enum spif_bd_error {
29  SPIF_BD_ERROR_OK = 0, /*!< no error */
30  SPIF_BD_ERROR_DEVICE_ERROR = BD_ERROR_DEVICE_ERROR, /*!< device specific error -4001 */
31  SPIF_BD_ERROR_PARSING_FAILED = -4002, /* SFDP Parsing failed */
32  SPIF_BD_ERROR_READY_FAILED = -4003, /* Wait for Memory Ready failed */
33  SPIF_BD_ERROR_WREN_FAILED = -4004, /* Write Enable Failed */
34  SPIF_BD_ERROR_INVALID_ERASE_PARAMS = -4005, /* Erase command not on sector aligned addresses or exceeds device size */
35 };
36 
37 
38 #define SPIF_MAX_REGIONS 10
39 #define MAX_NUM_OF_ERASE_TYPES 4
40 
41 /** BlockDevice for SFDP based flash devices over SPI bus
42  *
43  * @code
44  * // An example using SPI flash device on K82F target
45  * #include "mbed.h"
46  * #include "SPIFBlockDevice.h"
47  *
48  * // Create flash device on SPI bus with PTE5 as chip select
49  * SPIFBlockDevice spif(PTE2, PTE4, PTE1, PTE5);
50  *
51  * int main() {
52  * printf("spif test\n");
53  *
54  * // Initialize the SPI flash device and print the memory layout
55  * spif.init();
56  * printf("spif size: %llu\n", spif.size());
57  * printf("spif read size: %llu\n", spif.get_read_size());
58  * printf("spif program size: %llu\n", spif.get_program_size());
59  * printf("spif erase size: %llu\n", spif.get_erase_size());
60  *
61  * // Write "Hello World!" to the first block
62  * char *buffer = (char*)malloc(spif.get_erase_size());
63  * sprintf(buffer, "Hello World!\n");
64  * spif.erase(0, spif.get_erase_size());
65  * spif.program(buffer, 0, spif.get_erase_size());
66  *
67  * // Read back what was stored
68  * spif.read(buffer, 0, spif.get_erase_size());
69  * printf("%s", buffer);
70  *
71  * // Deinitialize the device
72  * spif.deinit();
73  * }
74  * @endcode
75  */
77 public:
78  /** Creates a SPIFBlockDevice on a SPI bus specified by pins
79  *
80  * @param mosi SPI master out, slave in pin
81  * @param miso SPI master in, slave out pin
82  * @param sclk SPI clock pin
83  * @param csel SPI chip select pin
84  * @param freq Clock speed of the SPI bus (defaults to 40MHz)
85  */
86  SPIFBlockDevice(PinName mosi, PinName miso, PinName sclk, PinName csel, int freq = 40000000);
87 
88  /** Initialize a block device
89  *
90  * @return SPIF_BD_ERROR_OK(0) - success
91  * SPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
92  * SPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
93  * SPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
94  */
95  virtual int init();
96 
97  /** Deinitialize a block device
98  *
99  * @return SPIF_BD_ERROR_OK(0) - success
100  */
101  virtual int deinit();
102 
103  /** Desctruct SPIFBlockDevice
104  */
106  {
107  deinit();
108  }
109 
110  /** Read blocks from a block device
111  *
112  * @param buffer Buffer to write blocks to
113  * @param addr Address of block to begin reading from
114  * @param size Size to read in bytes, must be a multiple of read block size
115  * @return SPIF_BD_ERROR_OK(0) - success
116  * SPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
117  */
118  virtual int read(void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
119 
120  /** Program blocks to a block device
121  *
122  * @note The blocks must have been erased prior to being programmed
123  *
124  * @param buffer Buffer of data to write to blocks
125  * @param addr Address of block to begin writing to
126  * @param size Size to write in bytes, must be a multiple of program block size
127  * @return SPIF_BD_ERROR_OK(0) - success
128  * SPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
129  * SPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
130  * SPIF_BD_ERROR_WREN_FAILED - Write Enable failed
131  */
132  virtual int program(const void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
133 
134  /** Erase blocks on a block device
135  *
136  * @note The state of an erased block is undefined until it has been programmed
137  *
138  * @param addr Address of block to begin erasing
139  * @param size Size to erase in bytes, must be a multiple of erase block size
140  * @return SPIF_BD_ERROR_OK(0) - success
141  * SPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
142  * SPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
143  * SPIF_BD_ERROR_INVALID_ERASE_PARAMS - Trying to erase unaligned address or size
144  */
145  virtual int erase(mbed::bd_addr_t addr, mbed::bd_size_t size);
146 
147  /** Get the size of a readable block
148  *
149  * @return Size of a readable block in bytes
150  */
151  virtual mbed::bd_size_t get_read_size() const;
152 
153  /** Get the size of a programable block
154  *
155  * @return Size of a programable block in bytes
156  * @note Must be a multiple of the read size
157  */
158  virtual mbed::bd_size_t get_program_size() const;
159 
160  /** Get the size of an erasable block
161  *
162  * @return Size of an erasable block in bytes
163  * @note Must be a multiple of the program size
164  */
165  virtual mbed::bd_size_t get_erase_size() const;
166 
167  /** Get the size of minimal erasable sector size of given address
168  *
169  * @param addr Any address within block queried for erase sector size (can be any address within flash size offset)
170  * @return Size of minimal erase sector size, in given address region, in bytes
171  * @note Must be a multiple of the program size
172  */
173  virtual mbed::bd_size_t get_erase_size(mbed::bd_addr_t addr) const;
174 
175  /** Get the value of storage byte after it was erased
176  *
177  * If get_erase_value returns a non-negative byte value, the underlying
178  * storage is set to that value when erased, and storage containing
179  * that value can be programmed without another erase.
180  *
181  * @return The value of storage when erased, or -1 if you can't
182  * rely on the value of erased storage
183  */
184  virtual int get_erase_value() const;
185 
186  /** Get the total size of the underlying device
187  *
188  * @return Size of the underlying device in bytes
189  */
190  virtual mbed::bd_size_t size() const;
191 
192  /** Get the BlockDevice class type.
193  *
194  * @return A string representation of the BlockDevice class type.
195  */
196  virtual const char *get_type() const;
197 
198 private:
199 
200  // Internal functions
201 
202  /****************************************/
203  /* SFDP Detection and Parsing Functions */
204  /****************************************/
205  // Parse SFDP Headers and retrieve Basic Param and Sector Map Tables (if exist)
206  int _sfdp_parse_sfdp_headers(uint32_t &basic_table_addr, size_t &basic_table_size,
207  uint32_t &sector_map_table_addr, size_t &sector_map_table_size);
208 
209  // Parse and Detect required Basic Parameters from Table
210  int _sfdp_parse_basic_param_table(uint32_t basic_table_addr, size_t basic_table_size);
211 
212  // Parse and read information required by Regions Sector Map
213  int _sfdp_parse_sector_map_table(uint32_t sector_map_table_addr, size_t sector_map_table_size);
214 
215  // Detect fastest read Bus mode supported by device
216  int _sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_ptr, int basic_param_table_size, int &read_inst);
217 
218  // Set Page size for program
219  unsigned int _sfdp_detect_page_size(uint8_t *basic_param_table_ptr, int basic_param_table_size);
220 
221  // Detect all supported erase types
222  int _sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size,
223  int &erase4k_inst,
224  int *erase_type_inst_arr, unsigned int *erase_type_size_arr);
225 
226  /***********************/
227  /* Utilities Functions */
228  /***********************/
229  // Find the region to which the given offset belongs to
230  int _utils_find_addr_region(bd_size_t offset) const;
231 
232  // Iterate on all supported Erase Types of the Region to which the offset belongs to.
233  // Iterates from highest type to lowest
234  int _utils_iterate_next_largest_erase_type(uint8_t &bitfield, int size, int offset, int boundry);
235 
236  /********************************/
237  /* Calls to SPI Driver APIs */
238  /********************************/
239  // Send Program => Write command to Driver
240  spif_bd_error _spi_send_program_command(int prog_inst, const void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
241 
242  // Send Read command to Driver
243  //spif_bd_error _spi_send_read_command(uint8_t read_inst, void *buffer, bd_addr_t addr, bd_size_t size);
244  spif_bd_error _spi_send_read_command(int read_inst, uint8_t *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size);
245 
246  // Send Erase Instruction using command_transfer command to Driver
247  spif_bd_error _spi_send_erase_command(int erase_inst, mbed::bd_addr_t addr, mbed::bd_size_t size);
248 
249  // Send Generic command_transfer command to Driver
250  spif_bd_error _spi_send_general_command(int instruction, mbed::bd_addr_t addr, char *tx_buffer,
251  size_t tx_length, char *rx_buffer, size_t rx_length);
252 
253  // Send set_frequency command to Driver
254  spif_bd_error _spi_set_frequency(int freq);
255  /********************************/
256 
257  // Soft Reset Flash Memory
258  int _reset_flash_mem();
259 
260  // Configure Write Enable in Status Register
261  int _set_write_enable();
262 
263  // Wait on status register until write not-in-progress
264  bool _is_mem_ready();
265 
266 private:
267  // Master side hardware
268  mbed::SPI _spi;
269  // Enable CS control (low/high) for SPI driver operations
270  mbed::DigitalOut _cs;
271 
272  // Mutex is used to protect Flash device for some SPI Driver commands that must be done sequentially with no other commands in between
273  // e.g. (1)Set Write Enable, (2)Program, (3)Wait Memory Ready
274  static SingletonPtr<PlatformMutex> _mutex;
275 
276  // Command Instructions
277  int _read_instruction;
278  int _prog_instruction;
279  int _erase_instruction;
280  int _erase4k_inst; // Legacy 4K erase instruction (default 0x20h)
281 
282  // Up To 4 Erase Types are supported by SFDP (each with its own command Instruction and Size)
283  int _erase_type_inst_arr[MAX_NUM_OF_ERASE_TYPES];
284  unsigned int _erase_type_size_arr[MAX_NUM_OF_ERASE_TYPES];
285 
286  // Sector Regions Map
287  int _regions_count; //number of regions
288  int _region_size_bytes[SPIF_MAX_REGIONS]; //regions size in bytes
289  bd_size_t _region_high_boundary[SPIF_MAX_REGIONS]; //region high address offset boundary
290  //Each Region can support a bit combination of any of the 4 Erase Types
291  uint8_t _region_erase_types_bitfield[SPIF_MAX_REGIONS];
292  unsigned int _min_common_erase_size; // minimal common erase size for all regions (0 if none exists)
293 
294  unsigned int _page_size_bytes; // Page size - 256 Bytes default
295  bd_size_t _device_size_bytes;
296 
297  // Bus configuration
298  unsigned int _address_size; // number of bytes for address
299  unsigned int _read_dummy_and_mode_cycles; // Number of Dummy and Mode Bits required by Read Bus Mode
300  unsigned int _write_dummy_and_mode_cycles; // Number of Dummy and Mode Bits required by Write Bus Mode
301  unsigned int _dummy_and_mode_cycles; // Number of Dummy and Mode Bits required by Current Bus Mode
302  uint32_t _init_ref_count;
303  bool _is_initialized;
304 };
305 
306 #endif /* MBED_SPIF_BLOCK_DEVICE_H */
virtual mbed::bd_size_t get_read_size() const
Get the size of a readable block.
virtual const char * get_type() const
Get the BlockDevice class type.
A hardware device capable of writing and reading blocks.
Definition: BlockDevice.h:47
virtual int init()
Initialize a block device.
virtual mbed::bd_size_t size() const
Get the total size of the underlying device.
SPIFBlockDevice(PinName mosi, PinName miso, PinName sclk, PinName csel, int freq=40000000)
Creates a SPIFBlockDevice on a SPI bus specified by pins.
virtual int get_erase_value() const
Get the value of storage byte after it was erased.
BlockDevice for SFDP based flash devices over SPI bus.
~SPIFBlockDevice()
Desctruct SPIFBlockDevice.
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 get_program_size() const
Get the size of a programable block.
virtual int program(const void *buffer, mbed::bd_addr_t addr, mbed::bd_size_t size)
Program blocks to a block device.
virtual int erase(mbed::bd_addr_t addr, mbed::bd_size_t size)
Erase blocks on a block device.
A digital output, used for setting the state of a pin.
Definition: DigitalOut.h:49
A SPI Master, used for communicating with SPI slave devices.
Definition: SPI.h:98
virtual int deinit()
Deinitialize a block device.
virtual mbed::bd_size_t get_erase_size() const
Get the size of an erasable block.
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.