Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of gr-peach-opencv-project-sd-card by
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 }
Generated on Tue Jul 12 2022 14:47:37 by
1.7.2
