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