Renesas GR-PEACH OpenCV Development / gr-peach-opencv-project-sd-card_update

Fork of gr-peach-opencv-project-sd-card by the do

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