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.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
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
Generated on Tue Jul 12 2022 13:54:51 by
1.7.2