Arun Raj / Mbed OS MAXREFDES101_SOURCE

Dependencies:   max32630fthr Adafruit_FeatherOLED USBDevice

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SPIFBlockDevice.cpp Source File

SPIFBlockDevice.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2016 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 
00017 #include "SPIFBlockDevice.h"
00018 
00019 
00020 // Read/write/erase sizes
00021 #define SPIF_READ_SIZE  1
00022 #define SPIF_PROG_SIZE  1
00023 #define SPIF_SE_SIZE    4096
00024 #define SPIF_TIMEOUT    10000
00025 
00026 // Debug available
00027 #define SPIF_DEBUG      0
00028 
00029 // MX25R Series Register Command Table. 
00030 enum ops {
00031     SPIF_NOP  = 0x00, // No operation
00032     SPIF_READ = 0x03, // Read data
00033     SPIF_PROG = 0x02, // Program data
00034     SPIF_SE   = 0x20, // 4KB Sector Erase 
00035     SPIF_CE   = 0xc7, // Chip Erase 
00036     SPIF_SFDP = 0x5a, // Read SFDP 
00037     SPIF_WREN = 0x06, // Write Enable 
00038     SPIF_WRDI = 0x04, // Write Disable
00039     SPIF_RDSR = 0x05, // Read Status Register 
00040     SPIF_RDID = 0x9f, // Read Manufacturer and JDEC Device ID 
00041 };
00042 
00043 // Status register from RDSR
00044 // [- stuff -| wel | wip ]
00045 // [-   6   -|  1  |  1  ]
00046 #define SPIF_WEL 0x2
00047 #define SPIF_WIP 0x1
00048 
00049  
00050 SPIFBlockDevice::SPIFBlockDevice(
00051     PinName mosi, PinName miso, PinName sclk, PinName cs, int freq)
00052     : _spi(mosi, miso, sclk), _cs(cs), _size(0)
00053 {
00054     _cs = 1;
00055     _spi.frequency(freq);
00056 }
00057 
00058 int SPIFBlockDevice::init()
00059 {
00060     // Check for vendor specific hacks, these should move into more general
00061     // handling when possible. RDID is not used to verify a device is attached.
00062     uint8_t id[3];
00063     _cmdread(SPIF_RDID, 0, 3, 0x0, id);
00064 
00065     switch (id[0]) {
00066         case 0xbf:
00067             // SST devices come preset with block protection
00068             // enabled for some regions, issue gbpu instruction to clear
00069             _wren();
00070             _cmdwrite(0x98, 0, 0, 0x0, NULL);
00071             break;
00072     }
00073 
00074     // Check that device is doing ok 
00075     int err = _sync();
00076     if (err) {
00077         return BD_ERROR_DEVICE_ERROR;
00078     }
00079 
00080     // Check JEDEC serial flash discoverable parameters for device
00081     // specific info
00082     uint8_t header[16];
00083     _cmdread(SPIF_SFDP, 4, 16, 0x0, header);
00084 
00085     // Verify SFDP signature for sanity
00086     // Also check that major/minor version is acceptable
00087     if (!(memcmp(&header[0], "SFDP", 4) == 0 && header[5] == 1)) {
00088         return BD_ERROR_DEVICE_ERROR;
00089     }
00090 
00091     // The SFDP spec indicates the standard table is always at offset 0
00092     // in the parameter headers, we check just to be safe
00093     if (!(header[8] == 0 && header[10] == 1)) {
00094         return BD_ERROR_DEVICE_ERROR;
00095     }
00096 
00097     // Parameter table pointer, spi commands are BE, SFDP is LE,
00098     // also sfdp command expects extra read wait byte
00099     uint32_t table_addr = (
00100         (header[14] << 24) |
00101         (header[13] << 16) |
00102         (header[12] << 8 ));
00103     uint8_t table[8];
00104     _cmdread(SPIF_SFDP, 4, 8, table_addr, table);
00105 
00106     // Check erase size, currently only supports 4kbytes
00107     // TODO support erase size != 4kbytes?
00108     // TODO support other erase opcodes from the sector descriptions
00109     if ((table[0] & 0x3) != 0x1 || table[1] != SPIF_SE) {
00110         return BD_ERROR_DEVICE_ERROR;
00111     }
00112 
00113     // Check address size, currently only supports 3byte addresses
00114     // TODO support address > 3bytes?
00115     // TODO check for devices larger than 2Gbits?
00116     if ((table[2] & 0x4) != 0 || (table[7] & 0x80) != 0) {
00117         return BD_ERROR_DEVICE_ERROR;
00118     }
00119 
00120     // Get device density, stored as size in bits - 1
00121     uint32_t density = (
00122         (table[7] << 24) |
00123         (table[6] << 16) |
00124         (table[5] << 8 ) |
00125         (table[4] << 0 ));
00126     _size = (density/8) + 1;
00127 
00128     return 0;
00129 }
00130 
00131 int SPIFBlockDevice::deinit()
00132 {
00133     // Latch write disable just to keep noise
00134     // from changing the device
00135     _cmdwrite(SPIF_WRDI, 0, 0, 0x0, NULL);
00136 
00137     return 0;
00138 }
00139 
00140 void SPIFBlockDevice::_cmdread(
00141         uint8_t op, uint32_t addrc, uint32_t retc,
00142         uint32_t addr, uint8_t *rets)
00143 {
00144 
00145     _cs = 0;
00146     _spi.write(op);
00147 
00148     for (uint32_t i = 0; i < addrc; i++) {
00149         _spi.write(0xff & (addr >> 8*(addrc-1 - i)));
00150     }
00151 
00152     for (uint32_t i = 0; i < retc; i++) {
00153         rets[i] = _spi.write(0);
00154     }
00155     _cs = 1;
00156 
00157 
00158 
00159     if (SPIF_DEBUG) {
00160         printf("spif <- %02x", op);
00161         for (uint32_t i = 0; i < addrc; i++) {
00162             if (i < addrc) {
00163                 printf("%02lx", 0xff & (addr >> 8*(addrc-1 - i)));
00164             } else {
00165                 printf("  ");
00166             }
00167         }
00168         printf(" ");
00169         for (uint32_t i = 0; i < 16 && i < retc; i++) {
00170             printf("%02x", rets[i]);
00171         }
00172         if (retc > 16) {
00173             printf("...");
00174         }
00175         printf("\n");
00176     }
00177 }
00178 
00179 void SPIFBlockDevice::_cmdwrite(
00180         uint8_t op, uint32_t addrc, uint32_t argc,
00181         uint32_t addr, const uint8_t *args)
00182 {
00183     _cs = 0;
00184     _spi.write(op);
00185 
00186     for (uint32_t i = 0; i < addrc; i++) {
00187         _spi.write(0xff & (addr >> 8*(addrc-1 - i)));
00188     }
00189 
00190     for (uint32_t i = 0; i < argc; i++) {
00191         _spi.write(args[i]);
00192     }
00193     _cs = 1;
00194 
00195     if (SPIF_DEBUG) {
00196         printf("spif -> %02x", op);
00197         for (uint32_t i = 0; i < addrc; i++) {
00198             if (i < addrc) {
00199                 printf("%02lx", 0xff & (addr >> 8*(addrc-1 - i)));
00200             } else {
00201                 printf("  ");
00202             }
00203         }
00204         printf(" ");
00205         for (uint32_t i = 0; i < 16 && i < argc; i++) {
00206             printf("%02x", args[i]);
00207         }
00208         if (argc > 16) {
00209             printf("...");
00210         }
00211         printf("\n");
00212     }
00213 }
00214 
00215 int SPIFBlockDevice::_sync()
00216 {
00217     for (int i = 0; i < SPIF_TIMEOUT; i++) {
00218         // Read status register until write not-in-progress
00219         uint8_t status;
00220         _cmdread(SPIF_RDSR, 0, 1, 0x0, &status);
00221 
00222         // Check WIP bit
00223         if (!(status & SPIF_WIP)) {
00224             return 0;
00225         }
00226 
00227         wait_ms(1);
00228     }
00229 
00230     return BD_ERROR_DEVICE_ERROR;
00231 }
00232 
00233 int SPIFBlockDevice::_wren()
00234 {
00235     _cmdwrite(SPIF_WREN, 0, 0, 0x0, NULL);
00236 
00237     for (int i = 0; i < SPIF_TIMEOUT; i++) {
00238         // Read status register until write latch is enabled
00239         uint8_t status;
00240         _cmdread(SPIF_RDSR, 0, 1, 0x0, &status);
00241 
00242         // Check WEL bit
00243         if (status & SPIF_WEL) {
00244             return 0;
00245         }
00246 
00247         wait_ms(1);
00248     }
00249 
00250     return BD_ERROR_DEVICE_ERROR;
00251 }
00252 
00253 int SPIFBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
00254 {
00255     // Check the address and size fit onto the chip.
00256     MBED_ASSERT(is_valid_read(addr, size));
00257 
00258     _cmdread(SPIF_READ, 3, size, addr, static_cast<uint8_t *>(buffer));
00259     return 0;
00260 }
00261  
00262 int SPIFBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size)
00263 {
00264     // Check the address and size fit onto the chip.
00265     MBED_ASSERT(is_valid_program(addr, size));
00266 
00267     while (size > 0) {
00268         int err = _wren();
00269         if (err) {
00270             return err;
00271         }
00272 
00273         // Write up to 256 bytes a page
00274         // TODO handle unaligned programs
00275         uint32_t off = addr % 256;
00276         uint32_t chunk = (off + size < 256) ? size : (256-off);
00277         _cmdwrite(SPIF_PROG, 3, chunk, addr, static_cast<const uint8_t *>(buffer));
00278         buffer = static_cast<const uint8_t*>(buffer) + chunk;
00279         addr += chunk;
00280         size -= chunk;
00281 
00282         wait_ms(1);
00283 
00284         err = _sync();
00285         if (err) {
00286             return err;
00287         }
00288     }
00289 
00290     return 0;
00291 }
00292 
00293 int SPIFBlockDevice::erase(bd_addr_t addr, bd_size_t size)
00294 {
00295     // Check the address and size fit onto the chip.
00296     MBED_ASSERT(is_valid_erase(addr, size));
00297 
00298     while (size > 0) {
00299         int err = _wren();
00300         if (err) {
00301             return err;
00302         }
00303     
00304         // Erase 4kbyte sectors
00305         // TODO support other erase sizes?
00306         uint32_t chunk = 4096;
00307         _cmdwrite(SPIF_SE, 3, 0, addr, NULL);
00308         addr += chunk;
00309         size -= chunk;
00310 
00311         err = _sync();
00312         if (err) {
00313             return err;
00314         }
00315     }
00316 
00317     return 0;
00318 }
00319 
00320 bd_size_t SPIFBlockDevice::get_read_size() const
00321 {
00322     return SPIF_READ_SIZE;
00323 }
00324 
00325 bd_size_t SPIFBlockDevice::get_program_size() const
00326 {
00327     return SPIF_PROG_SIZE;
00328 }
00329 
00330 bd_size_t SPIFBlockDevice::get_erase_size() const
00331 {
00332     return SPIF_SE_SIZE;
00333 }
00334 
00335 bd_size_t SPIFBlockDevice::size() const
00336 {
00337     return _size;
00338 }