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.
Dependencies: max32630fthr Adafruit_FeatherOLED USBDevice
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 // MX25R Series Register Command 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 // [- stuff -| wel | wip ] 00045 // [- 6 -| 1 | 1 ] 00046 #define SPIF_WEL 0x2 00047 #define SPIF_WIP 0x1 00048 00049 00050 SPIFBlockDevice::SPIFBlockDevice( 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 SPIFBlockDevice::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 uint32_t table_addr = ( 00100 (header[14] << 24) | 00101 (header[13] << 16) | 00102 (header[12] << 8 )); 00103 uint8_t table[8]; 00104 _cmdread(SPIF_SFDP, 4, 8, table_addr, table); 00105 00106 // Check erase size, currently only supports 4kbytes 00107 // TODO support erase size != 4kbytes? 00108 // TODO support other erase opcodes from the sector descriptions 00109 if ((table[0] & 0x3) != 0x1 || table[1] != SPIF_SE) { 00110 return BD_ERROR_DEVICE_ERROR; 00111 } 00112 00113 // Check address size, currently only supports 3byte addresses 00114 // TODO support address > 3bytes? 00115 // TODO check for devices larger than 2Gbits? 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 _size = (density/8) + 1; 00127 00128 return 0; 00129 } 00130 00131 int SPIFBlockDevice::deinit() 00132 { 00133 // Latch write disable just to keep noise 00134 // from changing the device 00135 _cmdwrite(SPIF_WRDI, 0, 0, 0x0, NULL); 00136 00137 return 0; 00138 } 00139 00140 void SPIFBlockDevice::_cmdread( 00141 uint8_t op, uint32_t addrc, uint32_t retc, 00142 uint32_t addr, uint8_t *rets) 00143 { 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 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 SPIFBlockDevice::_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 SPIFBlockDevice::_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 wait_ms(1); 00228 } 00229 00230 return BD_ERROR_DEVICE_ERROR; 00231 } 00232 00233 int SPIFBlockDevice::_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 wait_ms(1); 00248 } 00249 00250 return BD_ERROR_DEVICE_ERROR; 00251 } 00252 00253 int SPIFBlockDevice::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 SPIFBlockDevice::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 // TODO handle unaligned programs 00275 uint32_t off = addr % 256; 00276 uint32_t chunk = (off + size < 256) ? size : (256-off); 00277 _cmdwrite(SPIF_PROG, 3, chunk, addr, static_cast<const uint8_t *>(buffer)); 00278 buffer = static_cast<const uint8_t*>(buffer) + chunk; 00279 addr += chunk; 00280 size -= chunk; 00281 00282 wait_ms(1); 00283 00284 err = _sync(); 00285 if (err) { 00286 return err; 00287 } 00288 } 00289 00290 return 0; 00291 } 00292 00293 int SPIFBlockDevice::erase(bd_addr_t addr, bd_size_t size) 00294 { 00295 // Check the address and size fit onto the chip. 00296 MBED_ASSERT(is_valid_erase(addr, size)); 00297 00298 while (size > 0) { 00299 int err = _wren(); 00300 if (err) { 00301 return err; 00302 } 00303 00304 // Erase 4kbyte sectors 00305 // TODO support other erase sizes? 00306 uint32_t chunk = 4096; 00307 _cmdwrite(SPIF_SE, 3, 0, addr, NULL); 00308 addr += chunk; 00309 size -= chunk; 00310 00311 err = _sync(); 00312 if (err) { 00313 return err; 00314 } 00315 } 00316 00317 return 0; 00318 } 00319 00320 bd_size_t SPIFBlockDevice::get_read_size() const 00321 { 00322 return SPIF_READ_SIZE; 00323 } 00324 00325 bd_size_t SPIFBlockDevice::get_program_size() const 00326 { 00327 return SPIF_PROG_SIZE; 00328 } 00329 00330 bd_size_t SPIFBlockDevice::get_erase_size() const 00331 { 00332 return SPIF_SE_SIZE; 00333 } 00334 00335 bd_size_t SPIFBlockDevice::size() const 00336 { 00337 return _size; 00338 }
Generated on Tue Jul 12 2022 20:09:29 by
