Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SPIFReducedBlockDevice.cpp Source File

SPIFReducedBlockDevice.cpp

00001 
00002 /* mbed Microcontroller Library
00003  * Copyright (c) 2018 ARM Limited
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 #include "SPIFReducedBlockDevice.h"
00018 #include "rtos/ThisThread.h"
00019 
00020 using namespace mbed;
00021 
00022 // Read/write/erase sizes
00023 #define SPIF_READ_SIZE  1
00024 #define SPIF_PROG_SIZE  1
00025 #define SPIF_SE_SIZE    4096
00026 #define SPIF_TIMEOUT    10000
00027 
00028 // Debug available
00029 #define SPIF_DEBUG      0
00030 
00031 // Legacy SFDP Instruction Table.
00032 enum ops {
00033     SPIF_NOP  = 0x00, // No operation
00034     SPIF_READ = 0x03, // Read data
00035     SPIF_PROG = 0x02, // Program data
00036     SPIF_SE   = 0x20, // 4KB Sector Erase
00037     SPIF_CE   = 0xc7, // Chip Erase
00038     SPIF_SFDP = 0x5a, // Read SFDP
00039     SPIF_WREN = 0x06, // Write Enable
00040     SPIF_WRDI = 0x04, // Write Disable
00041     SPIF_RDSR = 0x05, // Read Status Register
00042     SPIF_RDID = 0x9f, // Read Manufacturer and JDEC Device ID
00043     SPIF_ULBPR = 0x98, // Clears all write-protection bits in the Block-Protection register
00044 };
00045 
00046 // Status register from RDSR
00047 // [---------| wel | wip ]
00048 // [-   6   -|  1  |  1  ]
00049 #define SPIF_WEL 0x2
00050 #define SPIF_WIP 0x1
00051 
00052 SPIFReducedBlockDevice::SPIFReducedBlockDevice(
00053     PinName mosi, PinName miso, PinName sclk, PinName cs, int freq)
00054     : _spi(mosi, miso, sclk), _cs(cs), _size(0)
00055 {
00056     _cs = 1;
00057     _spi.frequency(freq);
00058 }
00059 
00060 int SPIFReducedBlockDevice::init()
00061 {
00062     // Check for vendor specific hacks, these should move into more general
00063     // handling when possible. RDID is not used to verify a device is attached.
00064     uint8_t id[3];
00065     _cmdread(SPIF_RDID, 0, 3, 0x0, id);
00066 
00067     switch (id[0]) {
00068         case 0xbf:
00069             // SST devices come preset with block protection
00070             // enabled for some regions, issue global protection unlock to clear
00071             _wren();
00072             _cmdwrite(SPIF_ULBPR, 0, 0, 0x0, NULL);
00073             break;
00074     }
00075 
00076     // Check that device is doing ok
00077     int err = _sync();
00078     if (err) {
00079         return BD_ERROR_DEVICE_ERROR;
00080     }
00081 
00082     // Check JEDEC serial flash discoverable parameters for device
00083     // specific info
00084     uint8_t header[16];
00085     _cmdread(SPIF_SFDP, 4, 16, 0x0, header);
00086 
00087     // Verify SFDP signature for sanity
00088     // Also check that major/minor version is acceptable
00089     if (!(memcmp(&header[0], "SFDP", 4) == 0 && header[5] == 1)) {
00090         return BD_ERROR_DEVICE_ERROR;
00091     }
00092 
00093     // The SFDP spec indicates the standard table is always at offset 0
00094     // in the parameter headers, we check just to be safe
00095     if (!(header[8] == 0 && header[10] == 1)) {
00096         return BD_ERROR_DEVICE_ERROR;
00097     }
00098 
00099     // Parameter table pointer, spi commands are BE, SFDP is LE,
00100     // also sfdp command expects extra read wait byte
00101     // header 12-14 3 bytes building the parameter table address
00102     uint32_t table_addr = (
00103                               (header[14] << 24) |
00104                               (header[13] << 16) |
00105                               (header[12] << 8));
00106 
00107     uint8_t table[8];
00108     _cmdread(SPIF_SFDP, 4, 8, table_addr, table);
00109 
00110     // Check erase size, currently only supports 4kbytes
00111     if ((table[0] & 0x3) != 0x1 || table[1] != SPIF_SE) {
00112         // First byte of table, bits 0 and 1 = 0x1 indicating 4 KB Erase is supported
00113         // Second Byte of table = Sector Erase Command (0x20)
00114         return BD_ERROR_DEVICE_ERROR;
00115     }
00116 
00117     // Check address size, currently only supports 3byte addresses
00118     if ((table[2] & 0x4) != 0 || (table[7] & 0x80) != 0) {
00119         return BD_ERROR_DEVICE_ERROR;
00120     }
00121 
00122     // Get device density, stored as size in bits - 1
00123     uint32_t density = (
00124                            (table[7] << 24) |
00125                            (table[6] << 16) |
00126                            (table[5] << 8) |
00127                            (table[4] << 0));
00128     // Table bytes 5-8 : Bits 0|30 indicate Flash Density (size) in bits (divide by 8 for Bytes)
00129     _size = (density / 8) + 1;
00130 
00131     return 0;
00132 }
00133 
00134 int SPIFReducedBlockDevice::deinit()
00135 {
00136     // Latch write disable just to keep noise
00137     // from changing the device
00138     _cmdwrite(SPIF_WRDI, 0, 0, 0x0, NULL);
00139 
00140     return 0;
00141 }
00142 
00143 void SPIFReducedBlockDevice::_cmdread(
00144     uint8_t op, uint32_t addrc, uint32_t retc,
00145     uint32_t addr, uint8_t *rets)
00146 {
00147     _cs = 0;
00148     _spi.write(op);
00149 
00150     for (uint32_t i = 0; i < addrc; i++) {
00151         _spi.write(0xff & (addr >> 8 * (addrc - 1 - i)));
00152     }
00153 
00154     for (uint32_t i = 0; i < retc; i++) {
00155         rets[i] = _spi.write(0);
00156     }
00157     _cs = 1;
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 SPIFReducedBlockDevice::_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 SPIFReducedBlockDevice::_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         rtos::ThisThread::sleep_for(1);
00228     }
00229 
00230     return BD_ERROR_DEVICE_ERROR;
00231 }
00232 
00233 int SPIFReducedBlockDevice::_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         rtos::ThisThread::sleep_for(1);
00248     }
00249 
00250     return BD_ERROR_DEVICE_ERROR;
00251 }
00252 
00253 int SPIFReducedBlockDevice::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 SPIFReducedBlockDevice::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         uint32_t off = addr % 256;
00275         uint32_t chunk = (off + size < 256) ? size : (256 - off);
00276         _cmdwrite(SPIF_PROG, 3, chunk, addr, static_cast<const uint8_t *>(buffer));
00277         buffer = static_cast<const uint8_t *>(buffer) + chunk;
00278         addr += chunk;
00279         size -= chunk;
00280 
00281         rtos::ThisThread::sleep_for(1);
00282 
00283         err = _sync();
00284         if (err) {
00285             return err;
00286         }
00287     }
00288 
00289     return 0;
00290 }
00291 
00292 int SPIFReducedBlockDevice::erase(bd_addr_t addr, bd_size_t size)
00293 {
00294     // Check the address and size fit onto the chip.
00295     MBED_ASSERT(is_valid_erase(addr, size));
00296 
00297     while (size > 0) {
00298         int err = _wren();
00299         if (err) {
00300             return err;
00301         }
00302 
00303         // Erase 4kbyte sectors
00304         uint32_t chunk = 4096;
00305         _cmdwrite(SPIF_SE, 3, 0, addr, NULL);
00306         addr += chunk;
00307         size -= chunk;
00308 
00309         err = _sync();
00310         if (err) {
00311             return err;
00312         }
00313     }
00314 
00315     return 0;
00316 }
00317 
00318 bd_size_t SPIFReducedBlockDevice::get_read_size() const
00319 {
00320     return SPIF_READ_SIZE;
00321 }
00322 
00323 bd_size_t SPIFReducedBlockDevice::get_program_size() const
00324 {
00325     return SPIF_PROG_SIZE;
00326 }
00327 
00328 bd_size_t SPIFReducedBlockDevice::get_erase_size() const
00329 {
00330     return SPIF_SE_SIZE;
00331 }
00332 
00333 bd_size_t SPIFReducedBlockDevice::get_erase_size(bd_addr_t addr) const
00334 {
00335     return SPIF_SE_SIZE;
00336 }
00337 
00338 int SPIFReducedBlockDevice::get_erase_value() const
00339 {
00340     return 0xFF;
00341 }
00342 
00343 bd_size_t SPIFReducedBlockDevice::size() const
00344 {
00345     return _size;
00346 }
00347 
00348 const char *SPIFReducedBlockDevice::get_type() const
00349 {
00350     return "SPIFR";
00351 }
00352