Kev Mann / mbed-dev-OS5_10_4
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SPIFBlockDevice.h Source File

SPIFBlockDevice.h

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2018 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #ifndef MBED_SPIF_BLOCK_DEVICE_H
00017 #define MBED_SPIF_BLOCK_DEVICE_H
00018 
00019 #include "SPI.h"
00020 #include "DigitalOut.h"
00021 #include "BlockDevice.h"
00022 
00023 /** Enum spif standard error codes
00024  *
00025  *  @enum spif_bd_error
00026  */
00027 enum spif_bd_error {
00028     SPIF_BD_ERROR_OK                    = 0,     /*!< no error */
00029     SPIF_BD_ERROR_DEVICE_ERROR          = BD_ERROR_DEVICE_ERROR, /*!< device specific error -4001 */
00030     SPIF_BD_ERROR_PARSING_FAILED        = -4002, /* SFDP Parsing failed */
00031     SPIF_BD_ERROR_READY_FAILED          = -4003, /* Wait for  Mem Ready failed */
00032     SPIF_BD_ERROR_WREN_FAILED           = -4004, /* Write Enable Failed */
00033     SPIF_BD_ERROR_INVALID_ERASE_PARAMS  = -4005, /* Erase command not on sector aligned addresses or exceeds device size */
00034 };
00035 
00036 
00037 #define SPIF_MAX_REGIONS    10
00038 #define MAX_NUM_OF_ERASE_TYPES 4
00039 
00040 /** BlockDevice for SFDP based flash devices over SPI bus
00041  *
00042  *  @code
00043  *  // Here's an example using SPI flash device on K82F target
00044  *  #include "mbed.h"
00045  *  #include "SPIFBlockDevice.h"
00046  *
00047  *  // Create flash device on SPI bus with PTE5 as chip select
00048  *  SPIFBlockDevice spif(PTE2, PTE4, PTE1, PTE5);
00049  *
00050  *  int main() {
00051  *      printf("spif test\n");
00052  *
00053  *      // Initialize the SPI flash device and print the memory layout
00054  *      spif.init();
00055  *      printf("spif size: %llu\n",         spif.size());
00056  *      printf("spif read size: %llu\n",    spif.get_read_size());
00057  *      printf("spif program size: %llu\n", spif.get_program_size());
00058  *      printf("spif erase size: %llu\n",   spif.get_erase_size());
00059  *
00060  *      // Write "Hello World!" to the first block
00061  *      char *buffer = (char*)malloc(spif.get_erase_size());
00062  *      sprintf(buffer, "Hello World!\n");
00063  *      spif.erase(0, spif.get_erase_size());
00064  *      spif.program(buffer, 0, spif.get_erase_size());
00065  *
00066  *      // Read back what was stored
00067  *      spif.read(buffer, 0, spif.get_erase_size());
00068  *      printf("%s", buffer);
00069  *
00070  *      // Deinitialize the device
00071  *      spif.deinit();
00072  *  }
00073  *  @endcode
00074  */
00075 class SPIFBlockDevice : public BlockDevice {
00076 public:
00077     /** Creates a SPIFBlockDevice on a SPI bus specified by pins
00078      *
00079      *  @param mosi     SPI master out, slave in pin
00080      *  @param miso     SPI master in, slave out pin
00081      *  @param sclk     SPI clock pin
00082      *  @param csel     SPI chip select pin
00083      *  @param freq     Clock speed of the SPI bus (defaults to 40MHz)
00084      */
00085     SPIFBlockDevice(PinName mosi, PinName miso, PinName sclk, PinName csel, int freq = 40000000);
00086 
00087     /** Initialize a block device
00088      *
00089      *  @return         SPIF_BD_ERROR_OK(0) - success
00090      *                  SPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
00091      *                  SPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timedout
00092      *                  SPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
00093      */
00094     virtual int init();
00095 
00096     /** Deinitialize a block device
00097      *
00098      *  @return         SPIF_BD_ERROR_OK(0) - success
00099      */
00100     virtual int deinit();
00101 
00102     /** Desctruct SPIFBlockDevie
00103       */
00104     ~SPIFBlockDevice()
00105     {
00106         deinit();
00107     }
00108 
00109     /** Read blocks from a block device
00110      *
00111      *  @param buffer   Buffer to write blocks to
00112      *  @param addr     Address of block to begin reading from
00113      *  @param size     Size to read in bytes, must be a multiple of read block size
00114      *  @return         SPIF_BD_ERROR_OK(0) - success
00115      *                  SPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
00116      */
00117     virtual int read(void *buffer, bd_addr_t addr, bd_size_t size);
00118 
00119     /** Program blocks to a block device
00120      *
00121      *  The blocks must have been erased prior to being programmed
00122      *
00123      *  @param buffer   Buffer of data to write to blocks
00124      *  @param addr     Address of block to begin writing to
00125      *  @param size     Size to write in bytes, must be a multiple of program block size
00126      *  @return         SPIF_BD_ERROR_OK(0) - success
00127      *                  SPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
00128      *                  SPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
00129      *                  SPIF_BD_ERROR_WREN_FAILED - Write Enable failed
00130      */
00131     virtual int program(const void *buffer, bd_addr_t addr, bd_size_t size);
00132 
00133     /** Erase blocks on a block device
00134      *
00135      *  The state of an erased block is undefined until it has been programmed
00136      *
00137      *  @param addr     Address of block to begin erasing
00138      *  @param size     Size to erase in bytes, must be a multiple of erase block size
00139      *  @return         SPIF_BD_ERROR_OK(0) - success
00140      *                  SPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
00141      *                  SPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
00142      *                  SPIF_BD_ERROR_WREN_FAILED - Write Enable failed
00143      *                  SPIF_BD_ERROR_INVALID_ERASE_PARAMS - Trying to erase unaligned address or size
00144      */
00145     virtual int erase(bd_addr_t addr, bd_size_t size);
00146 
00147     /** Get the size of a readable block
00148      *
00149      *  @return         Size of a readable block in bytes
00150      */
00151     virtual bd_size_t get_read_size() const;
00152 
00153     /** Get the size of a programable block
00154      *
00155      *  @return         Size of a programable block in bytes
00156      *  @note Must be a multiple of the read size
00157      */
00158     virtual bd_size_t get_program_size() const;
00159 
00160     /** Get the size of a eraseable block
00161      *
00162      *  @return         Size of a eraseable block in bytes
00163      *  @note Must be a multiple of the program size
00164      */
00165     virtual bd_size_t get_erase_size() const;
00166 
00167     /** Get the size of minimal eraseable sector size of given address
00168      *
00169      *  @param addr     Any address within block queried for erase sector size (can be any address within flash size offset)
00170      *  @return         Size of minimal erase sector size, in given address region, in bytes
00171      *  @note Must be a multiple of the program size
00172      */
00173     virtual bd_size_t get_erase_size(bd_addr_t addr);
00174 
00175     /** Get the value of storage byte after it was erased
00176      *
00177      *  If get_erase_value returns a non-negative byte value, the underlying
00178      *  storage is set to that value when erased, and storage containing
00179      *  that value can be programmed without another erase.
00180      *
00181      *  @return         The value of storage when erased, or -1 if you can't
00182      *                  rely on the value of erased storage
00183      */
00184     virtual int get_erase_value() const;
00185 
00186     /** Get the total size of the underlying device
00187      *
00188      *  @return         Size of the underlying device in bytes
00189      */
00190     virtual bd_size_t size() const;
00191 
00192 private:
00193 
00194     // Internal functions
00195 
00196     /****************************************/
00197     /* SFDP Detection and Parsing Functions */
00198     /****************************************/
00199     // Parse SFDP Headers and retrieve Basic Param and Sector Map Tables (if exist)
00200     int _sfdp_parse_sfdp_headers(uint32_t &basic_table_addr, size_t &basic_table_size,
00201                                  uint32_t &sector_map_table_addr, size_t &sector_map_table_size);
00202 
00203     // Parse and Detect required Basic Parameters from Table
00204     int _sfdp_parse_basic_param_table(uint32_t basic_table_addr, size_t basic_table_size);
00205 
00206     // Parse and read information required by Regions Secotr Map
00207     int _sfdp_parse_sector_map_table(uint32_t sector_map_table_addr, size_t sector_map_table_size);
00208 
00209     // Detect fastest read Bus mode supported by device
00210     int _sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_ptr, int basic_param_table_size, int &read_inst);
00211 
00212     // Set Page size for program
00213     unsigned int _sfdp_detect_page_size(uint8_t *basic_param_table_ptr, int basic_param_table_size);
00214 
00215     // Detect all supported erase types
00216     int _sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size,
00217                                                int &erase4k_inst,
00218                                                int *erase_type_inst_arr, unsigned int *erase_type_size_arr);
00219 
00220     /***********************/
00221     /* Utilities Functions */
00222     /***********************/
00223     // Find the region to which the given offset belong to
00224     int _utils_find_addr_region(bd_size_t offset);
00225 
00226     // Iterate on all supported Erase Types of the Region to which the offset belong to.
00227     // Iterates from highest type to lowest
00228     int _utils_iterate_next_largest_erase_type(uint8_t &bitfield, int size, int offset, int boundry);
00229 
00230     /********************************/
00231     /*   Calls to SPI Driver APIs   */
00232     /********************************/
00233     // Send Program => Write command to Driver
00234     spif_bd_error _spi_send_program_command(int prog_inst, const void *buffer, bd_addr_t addr, bd_size_t size);
00235 
00236     // Send Read command to Driver
00237     //spif_bd_error _spi_send_read_command(uint8_t read_inst, void *buffer, bd_addr_t addr, bd_size_t size);
00238     spif_bd_error _spi_send_read_command(int read_inst, uint8_t *buffer, bd_addr_t addr, bd_size_t size);
00239 
00240     // Send Erase Instruction using command_transfer command to Driver
00241     spif_bd_error _spi_send_erase_command(int erase_inst, bd_addr_t addr, bd_size_t size);
00242 
00243     // Send Generic command_transfer command to Driver
00244     spif_bd_error _spi_send_general_command(int instruction, bd_addr_t addr, char *tx_buffer,
00245                                             size_t tx_length, char *rx_buffer, size_t rx_length);
00246 
00247     // Send set_frequency command to Driver
00248     spif_bd_error _spi_set_frequency(int freq);
00249     /********************************/
00250 
00251     // Soft Reset Flash Memory
00252     int _reset_flash_mem();
00253 
00254     // Configure Write Enable in Status Register
00255     int _set_write_enable();
00256 
00257     // Wait on status register until write not-in-progress
00258     bool _is_mem_ready();
00259 
00260 private:
00261     // Master side hardware
00262     mbed::SPI _spi;
00263     // Enable CS control (low/high) for SPI driver operatios
00264     mbed::DigitalOut _cs;
00265 
00266     // Mutex is used to protect Flash device for some SPI Driver commands that must be done sequentially with no other commands in between
00267     // e.g. (1)Set Write Enable, (2)Program, (3)Wait Memory Ready
00268     static SingletonPtr<PlatformMutex>  _mutex;
00269 
00270     // Command Instructions
00271     int _read_instruction;
00272     int _prog_instruction;
00273     int _erase_instruction;
00274     int _erase4k_inst;  // Legacy 4K erase instruction (default 0x20h)
00275 
00276     // Up To 4 Erase Types are supported by SFDP (each with its own command Instruction and Size)
00277     int _erase_type_inst_arr[MAX_NUM_OF_ERASE_TYPES];
00278     unsigned int _erase_type_size_arr[MAX_NUM_OF_ERASE_TYPES];
00279 
00280     // Sector Regions Map
00281     int _regions_count; //number of regions
00282     int _region_size_bytes[SPIF_MAX_REGIONS]; //regions size in bytes
00283     bd_size_t _region_high_boundary[SPIF_MAX_REGIONS]; //region high address offset boundary
00284     //Each Region can support a bit combination of any of the 4 Erase Types
00285     uint8_t _region_erase_types_bitfield[SPIF_MAX_REGIONS];
00286     unsigned int _min_common_erase_size; // minimal common erase size for all regions (0 if none exists)
00287 
00288     unsigned int _page_size_bytes; // Page size - 256 Bytes default
00289     bd_size_t _device_size_bytes;
00290 
00291     // Bus configuration
00292     unsigned int _address_size; // number of bytes for address
00293     unsigned int _read_dummy_and_mode_cycles; // Number of Dummy and Mode Bits required by Read Bus Mode
00294     unsigned int _write_dummy_and_mode_cycles; // Number of Dummy and Mode Bits required by Write Bus Mode
00295     unsigned int _dummy_and_mode_cycles; // Number of Dummy and Mode Bits required by Current Bus Mode
00296     uint32_t _init_ref_count;
00297     bool _is_initialized;
00298 };
00299 
00300 #endif  /* MBED_SPIF_BLOCK_DEVICE_H */