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.
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 "mbed_wait_api.h" 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 // Legacy SFDP Instruction 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 // [---------| wel | wip ] 00045 // [- 6 -| 1 | 1 ] 00046 #define SPIF_WEL 0x2 00047 #define SPIF_WIP 0x1 00048 00049 00050 SPIFReducedBlockDevice::SPIFReducedBlockDevice( 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 SPIFReducedBlockDevice::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 // header 12-14 3 bytes building the parameter table address 00100 uint32_t table_addr = ( 00101 (header[14] << 24) | 00102 (header[13] << 16) | 00103 (header[12] << 8 )); 00104 00105 uint8_t table[8]; 00106 _cmdread(SPIF_SFDP, 4, 8, table_addr, table); 00107 00108 // Check erase size, currently only supports 4kbytes 00109 if ((table[0] & 0x3) != 0x1 || table[1] != SPIF_SE) { 00110 // First byte of table, bits 0 and 1 = 0x1 indicating 4 KB Erase is supported 00111 // Second Byte of table = Sector Erase Command (0x20) 00112 return BD_ERROR_DEVICE_ERROR; 00113 } 00114 00115 // Check address size, currently only supports 3byte addresses 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 // Table bytes 5-8 : Bits 0|30 indicate Flash Density (size) in bits (divide by 8 for Bytes) 00127 _size = (density / 8) + 1; 00128 00129 return 0; 00130 } 00131 00132 int SPIFReducedBlockDevice::deinit() 00133 { 00134 // Latch write disable just to keep noise 00135 // from changing the device 00136 _cmdwrite(SPIF_WRDI, 0, 0, 0x0, NULL); 00137 00138 return 0; 00139 } 00140 00141 void SPIFReducedBlockDevice::_cmdread( 00142 uint8_t op, uint32_t addrc, uint32_t retc, 00143 uint32_t addr, uint8_t *rets) 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 if (SPIF_DEBUG) { 00158 printf("spif <- %02x", op); 00159 for (uint32_t i = 0; i < addrc; i++) { 00160 if (i < addrc) { 00161 printf("%02lx", 0xff & (addr >> 8 * (addrc - 1 - i))); 00162 } else { 00163 printf(" "); 00164 } 00165 } 00166 printf(" "); 00167 for (uint32_t i = 0; i < 16 && i < retc; i++) { 00168 printf("%02x", rets[i]); 00169 } 00170 if (retc > 16) { 00171 printf("..."); 00172 } 00173 printf("\n"); 00174 } 00175 } 00176 00177 void SPIFReducedBlockDevice::_cmdwrite( 00178 uint8_t op, uint32_t addrc, uint32_t argc, 00179 uint32_t addr, const uint8_t *args) 00180 { 00181 _cs = 0; 00182 _spi.write(op); 00183 00184 for (uint32_t i = 0; i < addrc; i++) { 00185 _spi.write(0xff & (addr >> 8 * (addrc - 1 - i))); 00186 } 00187 00188 for (uint32_t i = 0; i < argc; i++) { 00189 _spi.write(args[i]); 00190 } 00191 _cs = 1; 00192 00193 if (SPIF_DEBUG) { 00194 printf("spif -> %02x", op); 00195 for (uint32_t i = 0; i < addrc; i++) { 00196 if (i < addrc) { 00197 printf("%02lx", 0xff & (addr >> 8 * (addrc - 1 - i))); 00198 } else { 00199 printf(" "); 00200 } 00201 } 00202 printf(" "); 00203 for (uint32_t i = 0; i < 16 && i < argc; i++) { 00204 printf("%02x", args[i]); 00205 } 00206 if (argc > 16) { 00207 printf("..."); 00208 } 00209 printf("\n"); 00210 } 00211 } 00212 00213 int SPIFReducedBlockDevice::_sync() 00214 { 00215 for (int i = 0; i < SPIF_TIMEOUT; i++) { 00216 // Read status register until write not-in-progress 00217 uint8_t status; 00218 _cmdread(SPIF_RDSR, 0, 1, 0x0, &status); 00219 00220 // Check WIP bit 00221 if (!(status & SPIF_WIP)) { 00222 return 0; 00223 } 00224 00225 wait_ms(1); 00226 } 00227 00228 return BD_ERROR_DEVICE_ERROR; 00229 } 00230 00231 int SPIFReducedBlockDevice::_wren() 00232 { 00233 _cmdwrite(SPIF_WREN, 0, 0, 0x0, NULL); 00234 00235 for (int i = 0; i < SPIF_TIMEOUT; i++) { 00236 // Read status register until write latch is enabled 00237 uint8_t status; 00238 _cmdread(SPIF_RDSR, 0, 1, 0x0, &status); 00239 00240 // Check WEL bit 00241 if (status & SPIF_WEL) { 00242 return 0; 00243 } 00244 00245 wait_ms(1); 00246 } 00247 00248 return BD_ERROR_DEVICE_ERROR; 00249 } 00250 00251 int SPIFReducedBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size) 00252 { 00253 // Check the address and size fit onto the chip. 00254 MBED_ASSERT(is_valid_read(addr, size)); 00255 00256 _cmdread(SPIF_READ, 3, size, addr, static_cast<uint8_t *>(buffer)); 00257 return 0; 00258 } 00259 00260 int SPIFReducedBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size) 00261 { 00262 // Check the address and size fit onto the chip. 00263 MBED_ASSERT(is_valid_program(addr, size)); 00264 00265 while (size > 0) { 00266 int err = _wren(); 00267 if (err) { 00268 return err; 00269 } 00270 00271 // Write up to 256 bytes a page 00272 uint32_t off = addr % 256; 00273 uint32_t chunk = (off + size < 256) ? size : (256 - off); 00274 _cmdwrite(SPIF_PROG, 3, chunk, addr, static_cast<const uint8_t *>(buffer)); 00275 buffer = static_cast<const uint8_t *>(buffer) + chunk; 00276 addr += chunk; 00277 size -= chunk; 00278 00279 wait_ms(1); 00280 00281 err = _sync(); 00282 if (err) { 00283 return err; 00284 } 00285 } 00286 00287 return 0; 00288 } 00289 00290 int SPIFReducedBlockDevice::erase(bd_addr_t addr, bd_size_t size) 00291 { 00292 // Check the address and size fit onto the chip. 00293 MBED_ASSERT(is_valid_erase(addr, size)); 00294 00295 while (size > 0) { 00296 int err = _wren(); 00297 if (err) { 00298 return err; 00299 } 00300 00301 // Erase 4kbyte sectors 00302 uint32_t chunk = 4096; 00303 _cmdwrite(SPIF_SE, 3, 0, addr, NULL); 00304 addr += chunk; 00305 size -= chunk; 00306 00307 err = _sync(); 00308 if (err) { 00309 return err; 00310 } 00311 } 00312 00313 return 0; 00314 } 00315 00316 bd_size_t SPIFReducedBlockDevice::get_read_size() const 00317 { 00318 return SPIF_READ_SIZE; 00319 } 00320 00321 bd_size_t SPIFReducedBlockDevice::get_program_size() const 00322 { 00323 return SPIF_PROG_SIZE; 00324 } 00325 00326 bd_size_t SPIFReducedBlockDevice::get_erase_size() const 00327 { 00328 return SPIF_SE_SIZE; 00329 } 00330 00331 bd_size_t SPIFReducedBlockDevice::get_erase_size(bd_addr_t addr) const 00332 { 00333 return SPIF_SE_SIZE; 00334 } 00335 00336 int SPIFReducedBlockDevice::get_erase_value() const 00337 { 00338 return 0xFF; 00339 } 00340 00341 bd_size_t SPIFReducedBlockDevice::size() const 00342 { 00343 return _size; 00344 }
Generated on Tue Jul 12 2022 20:52:57 by
1.7.2