x

Dependents:   20180621_FT813

Committer:
JackB
Date:
Mon Jul 23 12:22:51 2018 +0000
Revision:
0:b4f61c49c866
SPIF

Who changed what in which revision?

UserRevisionLine numberNew contents of line
JackB 0:b4f61c49c866 1 /* mbed Microcontroller Library
JackB 0:b4f61c49c866 2 * Copyright (c) 2016 ARM Limited
JackB 0:b4f61c49c866 3 *
JackB 0:b4f61c49c866 4 * Licensed under the Apache License, Version 2.0 (the "License");
JackB 0:b4f61c49c866 5 * you may not use this file except in compliance with the License.
JackB 0:b4f61c49c866 6 * You may obtain a copy of the License at
JackB 0:b4f61c49c866 7 *
JackB 0:b4f61c49c866 8 * http://www.apache.org/licenses/LICENSE-2.0
JackB 0:b4f61c49c866 9 *
JackB 0:b4f61c49c866 10 * Unless required by applicable law or agreed to in writing, software
JackB 0:b4f61c49c866 11 * distributed under the License is distributed on an "AS IS" BASIS,
JackB 0:b4f61c49c866 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
JackB 0:b4f61c49c866 13 * See the License for the specific language governing permissions and
JackB 0:b4f61c49c866 14 * limitations under the License.
JackB 0:b4f61c49c866 15 */
JackB 0:b4f61c49c866 16
JackB 0:b4f61c49c866 17 #include "SPIFBlockDevice.h"
JackB 0:b4f61c49c866 18
JackB 0:b4f61c49c866 19
JackB 0:b4f61c49c866 20 // Read/write/erase sizes
JackB 0:b4f61c49c866 21 #define SPIF_READ_SIZE 1
JackB 0:b4f61c49c866 22 #define SPIF_PROG_SIZE 1
JackB 0:b4f61c49c866 23 #define SPIF_SE_SIZE 4096
JackB 0:b4f61c49c866 24 #define SPIF_TIMEOUT 10000
JackB 0:b4f61c49c866 25
JackB 0:b4f61c49c866 26 // Debug available
JackB 0:b4f61c49c866 27 #define SPIF_DEBUG 0
JackB 0:b4f61c49c866 28
JackB 0:b4f61c49c866 29 // MX25R Series Register Command Table.
JackB 0:b4f61c49c866 30 enum ops {
JackB 0:b4f61c49c866 31 SPIF_NOP = 0x00, // No operation
JackB 0:b4f61c49c866 32 SPIF_READ = 0x03, // Read data
JackB 0:b4f61c49c866 33 SPIF_PROG = 0x02, // Program data
JackB 0:b4f61c49c866 34 SPIF_SE = 0x20, // 4KB Sector Erase
JackB 0:b4f61c49c866 35 SPIF_CE = 0xc7, // Chip Erase
JackB 0:b4f61c49c866 36 SPIF_SFDP = 0x5a, // Read SFDP
JackB 0:b4f61c49c866 37 SPIF_WREN = 0x06, // Write Enable
JackB 0:b4f61c49c866 38 SPIF_WRDI = 0x04, // Write Disable
JackB 0:b4f61c49c866 39 SPIF_RDSR = 0x05, // Read Status Register
JackB 0:b4f61c49c866 40 SPIF_RDID = 0x9f, // Read Manufacturer and JDEC Device ID
JackB 0:b4f61c49c866 41 };
JackB 0:b4f61c49c866 42
JackB 0:b4f61c49c866 43 // Status register from RDSR
JackB 0:b4f61c49c866 44 // [- stuff -| wel | wip ]
JackB 0:b4f61c49c866 45 // [- 6 -| 1 | 1 ]
JackB 0:b4f61c49c866 46 #define SPIF_WEL 0x2
JackB 0:b4f61c49c866 47 #define SPIF_WIP 0x1
JackB 0:b4f61c49c866 48
JackB 0:b4f61c49c866 49
JackB 0:b4f61c49c866 50 SPIFBlockDevice::SPIFBlockDevice(
JackB 0:b4f61c49c866 51 PinName mosi, PinName miso, PinName sclk, PinName cs, int freq)
JackB 0:b4f61c49c866 52 : _spi(mosi, miso, sclk), _cs(cs), _size(0)
JackB 0:b4f61c49c866 53 {
JackB 0:b4f61c49c866 54 _cs = 1;
JackB 0:b4f61c49c866 55 _spi.frequency(freq);
JackB 0:b4f61c49c866 56 }
JackB 0:b4f61c49c866 57
JackB 0:b4f61c49c866 58 int SPIFBlockDevice::init()
JackB 0:b4f61c49c866 59 {
JackB 0:b4f61c49c866 60 // Check for vendor specific hacks, these should move into more general
JackB 0:b4f61c49c866 61 // handling when possible. RDID is not used to verify a device is attached.
JackB 0:b4f61c49c866 62 uint8_t id[3];
JackB 0:b4f61c49c866 63 _cmdread(SPIF_RDID, 0, 3, 0x0, id);
JackB 0:b4f61c49c866 64
JackB 0:b4f61c49c866 65 switch (id[0]) {
JackB 0:b4f61c49c866 66 case 0xbf:
JackB 0:b4f61c49c866 67 // SST devices come preset with block protection
JackB 0:b4f61c49c866 68 // enabled for some regions, issue gbpu instruction to clear
JackB 0:b4f61c49c866 69 _wren();
JackB 0:b4f61c49c866 70 _cmdwrite(0x98, 0, 0, 0x0, NULL);
JackB 0:b4f61c49c866 71 break;
JackB 0:b4f61c49c866 72 }
JackB 0:b4f61c49c866 73
JackB 0:b4f61c49c866 74 // Check that device is doing ok
JackB 0:b4f61c49c866 75 int err = _sync();
JackB 0:b4f61c49c866 76 if (err) {
JackB 0:b4f61c49c866 77 return BD_ERROR_DEVICE_ERROR;
JackB 0:b4f61c49c866 78 }
JackB 0:b4f61c49c866 79
JackB 0:b4f61c49c866 80 // Check JEDEC serial flash discoverable parameters for device
JackB 0:b4f61c49c866 81 // specific info
JackB 0:b4f61c49c866 82 uint8_t header[16];
JackB 0:b4f61c49c866 83 _cmdread(SPIF_SFDP, 4, 16, 0x0, header);
JackB 0:b4f61c49c866 84
JackB 0:b4f61c49c866 85 // Verify SFDP signature for sanity
JackB 0:b4f61c49c866 86 // Also check that major/minor version is acceptable
JackB 0:b4f61c49c866 87 if (!(memcmp(&header[0], "SFDP", 4) == 0 && header[5] == 1)) {
JackB 0:b4f61c49c866 88 return BD_ERROR_DEVICE_ERROR;
JackB 0:b4f61c49c866 89 }
JackB 0:b4f61c49c866 90
JackB 0:b4f61c49c866 91 // The SFDP spec indicates the standard table is always at offset 0
JackB 0:b4f61c49c866 92 // in the parameter headers, we check just to be safe
JackB 0:b4f61c49c866 93 if (!(header[8] == 0 && header[10] == 1)) {
JackB 0:b4f61c49c866 94 return BD_ERROR_DEVICE_ERROR;
JackB 0:b4f61c49c866 95 }
JackB 0:b4f61c49c866 96
JackB 0:b4f61c49c866 97 // Parameter table pointer, spi commands are BE, SFDP is LE,
JackB 0:b4f61c49c866 98 // also sfdp command expects extra read wait byte
JackB 0:b4f61c49c866 99 uint32_t table_addr = (
JackB 0:b4f61c49c866 100 (header[14] << 24) |
JackB 0:b4f61c49c866 101 (header[13] << 16) |
JackB 0:b4f61c49c866 102 (header[12] << 8 ));
JackB 0:b4f61c49c866 103 uint8_t table[8];
JackB 0:b4f61c49c866 104 _cmdread(SPIF_SFDP, 4, 8, table_addr, table);
JackB 0:b4f61c49c866 105
JackB 0:b4f61c49c866 106 // Check erase size, currently only supports 4kbytes
JackB 0:b4f61c49c866 107 // TODO support erase size != 4kbytes?
JackB 0:b4f61c49c866 108 // TODO support other erase opcodes from the sector descriptions
JackB 0:b4f61c49c866 109 if ((table[0] & 0x3) != 0x1 || table[1] != SPIF_SE) {
JackB 0:b4f61c49c866 110 return BD_ERROR_DEVICE_ERROR;
JackB 0:b4f61c49c866 111 }
JackB 0:b4f61c49c866 112
JackB 0:b4f61c49c866 113 // Check address size, currently only supports 3byte addresses
JackB 0:b4f61c49c866 114 // TODO support address > 3bytes?
JackB 0:b4f61c49c866 115 // TODO check for devices larger than 2Gbits?
JackB 0:b4f61c49c866 116 if ((table[2] & 0x4) != 0 || (table[7] & 0x80) != 0) {
JackB 0:b4f61c49c866 117 return BD_ERROR_DEVICE_ERROR;
JackB 0:b4f61c49c866 118 }
JackB 0:b4f61c49c866 119
JackB 0:b4f61c49c866 120 // Get device density, stored as size in bits - 1
JackB 0:b4f61c49c866 121 uint32_t density = (
JackB 0:b4f61c49c866 122 (table[7] << 24) |
JackB 0:b4f61c49c866 123 (table[6] << 16) |
JackB 0:b4f61c49c866 124 (table[5] << 8 ) |
JackB 0:b4f61c49c866 125 (table[4] << 0 ));
JackB 0:b4f61c49c866 126 _size = (density/8) + 1;
JackB 0:b4f61c49c866 127
JackB 0:b4f61c49c866 128 return 0;
JackB 0:b4f61c49c866 129 }
JackB 0:b4f61c49c866 130
JackB 0:b4f61c49c866 131 int SPIFBlockDevice::deinit()
JackB 0:b4f61c49c866 132 {
JackB 0:b4f61c49c866 133 // Latch write disable just to keep noise
JackB 0:b4f61c49c866 134 // from changing the device
JackB 0:b4f61c49c866 135 _cmdwrite(SPIF_WRDI, 0, 0, 0x0, NULL);
JackB 0:b4f61c49c866 136
JackB 0:b4f61c49c866 137 return 0;
JackB 0:b4f61c49c866 138 }
JackB 0:b4f61c49c866 139
JackB 0:b4f61c49c866 140 void SPIFBlockDevice::_cmdread(
JackB 0:b4f61c49c866 141 uint8_t op, uint32_t addrc, uint32_t retc,
JackB 0:b4f61c49c866 142 uint32_t addr, uint8_t *rets)
JackB 0:b4f61c49c866 143 {
JackB 0:b4f61c49c866 144 _cs = 0;
JackB 0:b4f61c49c866 145 _spi.write(op);
JackB 0:b4f61c49c866 146
JackB 0:b4f61c49c866 147 for (uint32_t i = 0; i < addrc; i++) {
JackB 0:b4f61c49c866 148 _spi.write(0xff & (addr >> 8*(addrc-1 - i)));
JackB 0:b4f61c49c866 149 }
JackB 0:b4f61c49c866 150
JackB 0:b4f61c49c866 151 for (uint32_t i = 0; i < retc; i++) {
JackB 0:b4f61c49c866 152 rets[i] = _spi.write(0);
JackB 0:b4f61c49c866 153 }
JackB 0:b4f61c49c866 154 _cs = 1;
JackB 0:b4f61c49c866 155
JackB 0:b4f61c49c866 156 if (SPIF_DEBUG) {
JackB 0:b4f61c49c866 157 printf("spif <- %02x", op);
JackB 0:b4f61c49c866 158 for (uint32_t i = 0; i < addrc; i++) {
JackB 0:b4f61c49c866 159 if (i < addrc) {
JackB 0:b4f61c49c866 160 printf("%02lx", 0xff & (addr >> 8*(addrc-1 - i)));
JackB 0:b4f61c49c866 161 } else {
JackB 0:b4f61c49c866 162 printf(" ");
JackB 0:b4f61c49c866 163 }
JackB 0:b4f61c49c866 164 }
JackB 0:b4f61c49c866 165 printf(" ");
JackB 0:b4f61c49c866 166 for (uint32_t i = 0; i < 16 && i < retc; i++) {
JackB 0:b4f61c49c866 167 printf("%02x", rets[i]);
JackB 0:b4f61c49c866 168 }
JackB 0:b4f61c49c866 169 if (retc > 16) {
JackB 0:b4f61c49c866 170 printf("...");
JackB 0:b4f61c49c866 171 }
JackB 0:b4f61c49c866 172 printf("\n");
JackB 0:b4f61c49c866 173 }
JackB 0:b4f61c49c866 174 }
JackB 0:b4f61c49c866 175
JackB 0:b4f61c49c866 176 void SPIFBlockDevice::_cmdwrite(
JackB 0:b4f61c49c866 177 uint8_t op, uint32_t addrc, uint32_t argc,
JackB 0:b4f61c49c866 178 uint32_t addr, const uint8_t *args)
JackB 0:b4f61c49c866 179 {
JackB 0:b4f61c49c866 180 _cs = 0;
JackB 0:b4f61c49c866 181 _spi.write(op);
JackB 0:b4f61c49c866 182
JackB 0:b4f61c49c866 183 for (uint32_t i = 0; i < addrc; i++) {
JackB 0:b4f61c49c866 184 _spi.write(0xff & (addr >> 8*(addrc-1 - i)));
JackB 0:b4f61c49c866 185 }
JackB 0:b4f61c49c866 186
JackB 0:b4f61c49c866 187 for (uint32_t i = 0; i < argc; i++) {
JackB 0:b4f61c49c866 188 _spi.write(args[i]);
JackB 0:b4f61c49c866 189 }
JackB 0:b4f61c49c866 190 _cs = 1;
JackB 0:b4f61c49c866 191
JackB 0:b4f61c49c866 192 if (SPIF_DEBUG) {
JackB 0:b4f61c49c866 193 printf("spif -> %02x", op);
JackB 0:b4f61c49c866 194 for (uint32_t i = 0; i < addrc; i++) {
JackB 0:b4f61c49c866 195 if (i < addrc) {
JackB 0:b4f61c49c866 196 printf("%02lx", 0xff & (addr >> 8*(addrc-1 - i)));
JackB 0:b4f61c49c866 197 } else {
JackB 0:b4f61c49c866 198 printf(" ");
JackB 0:b4f61c49c866 199 }
JackB 0:b4f61c49c866 200 }
JackB 0:b4f61c49c866 201 printf(" ");
JackB 0:b4f61c49c866 202 for (uint32_t i = 0; i < 16 && i < argc; i++) {
JackB 0:b4f61c49c866 203 printf("%02x", args[i]);
JackB 0:b4f61c49c866 204 }
JackB 0:b4f61c49c866 205 if (argc > 16) {
JackB 0:b4f61c49c866 206 printf("...");
JackB 0:b4f61c49c866 207 }
JackB 0:b4f61c49c866 208 printf("\n");
JackB 0:b4f61c49c866 209 }
JackB 0:b4f61c49c866 210 }
JackB 0:b4f61c49c866 211
JackB 0:b4f61c49c866 212 int SPIFBlockDevice::_sync()
JackB 0:b4f61c49c866 213 {
JackB 0:b4f61c49c866 214 for (int i = 0; i < SPIF_TIMEOUT; i++) {
JackB 0:b4f61c49c866 215 // Read status register until write not-in-progress
JackB 0:b4f61c49c866 216 uint8_t status;
JackB 0:b4f61c49c866 217 _cmdread(SPIF_RDSR, 0, 1, 0x0, &status);
JackB 0:b4f61c49c866 218
JackB 0:b4f61c49c866 219 // Check WIP bit
JackB 0:b4f61c49c866 220 if (!(status & SPIF_WIP)) {
JackB 0:b4f61c49c866 221 return 0;
JackB 0:b4f61c49c866 222 }
JackB 0:b4f61c49c866 223
JackB 0:b4f61c49c866 224 wait_ms(1);
JackB 0:b4f61c49c866 225 }
JackB 0:b4f61c49c866 226
JackB 0:b4f61c49c866 227 return BD_ERROR_DEVICE_ERROR;
JackB 0:b4f61c49c866 228 }
JackB 0:b4f61c49c866 229
JackB 0:b4f61c49c866 230 int SPIFBlockDevice::_wren()
JackB 0:b4f61c49c866 231 {
JackB 0:b4f61c49c866 232 _cmdwrite(SPIF_WREN, 0, 0, 0x0, NULL);
JackB 0:b4f61c49c866 233
JackB 0:b4f61c49c866 234 for (int i = 0; i < SPIF_TIMEOUT; i++) {
JackB 0:b4f61c49c866 235 // Read status register until write latch is enabled
JackB 0:b4f61c49c866 236 uint8_t status;
JackB 0:b4f61c49c866 237 _cmdread(SPIF_RDSR, 0, 1, 0x0, &status);
JackB 0:b4f61c49c866 238
JackB 0:b4f61c49c866 239 // Check WEL bit
JackB 0:b4f61c49c866 240 if (status & SPIF_WEL) {
JackB 0:b4f61c49c866 241 return 0;
JackB 0:b4f61c49c866 242 }
JackB 0:b4f61c49c866 243
JackB 0:b4f61c49c866 244 wait_ms(1);
JackB 0:b4f61c49c866 245 }
JackB 0:b4f61c49c866 246
JackB 0:b4f61c49c866 247 return BD_ERROR_DEVICE_ERROR;
JackB 0:b4f61c49c866 248 }
JackB 0:b4f61c49c866 249
JackB 0:b4f61c49c866 250 int SPIFBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
JackB 0:b4f61c49c866 251 {
JackB 0:b4f61c49c866 252 // Check the address and size fit onto the chip.
JackB 0:b4f61c49c866 253 MBED_ASSERT(is_valid_read(addr, size));
JackB 0:b4f61c49c866 254
JackB 0:b4f61c49c866 255 _cmdread(SPIF_READ, 3, size, addr, static_cast<uint8_t *>(buffer));
JackB 0:b4f61c49c866 256 return 0;
JackB 0:b4f61c49c866 257 }
JackB 0:b4f61c49c866 258
JackB 0:b4f61c49c866 259 int SPIFBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size)
JackB 0:b4f61c49c866 260 {
JackB 0:b4f61c49c866 261 // Check the address and size fit onto the chip.
JackB 0:b4f61c49c866 262 MBED_ASSERT(is_valid_program(addr, size));
JackB 0:b4f61c49c866 263
JackB 0:b4f61c49c866 264 while (size > 0) {
JackB 0:b4f61c49c866 265 int err = _wren();
JackB 0:b4f61c49c866 266 if (err) {
JackB 0:b4f61c49c866 267 return err;
JackB 0:b4f61c49c866 268 }
JackB 0:b4f61c49c866 269
JackB 0:b4f61c49c866 270 // Write up to 256 bytes a page
JackB 0:b4f61c49c866 271 // TODO handle unaligned programs
JackB 0:b4f61c49c866 272 uint32_t off = addr % 256;
JackB 0:b4f61c49c866 273 uint32_t chunk = (off + size < 256) ? size : (256-off);
JackB 0:b4f61c49c866 274 _cmdwrite(SPIF_PROG, 3, chunk, addr, static_cast<const uint8_t *>(buffer));
JackB 0:b4f61c49c866 275 buffer = static_cast<const uint8_t*>(buffer) + chunk;
JackB 0:b4f61c49c866 276 addr += chunk;
JackB 0:b4f61c49c866 277 size -= chunk;
JackB 0:b4f61c49c866 278
JackB 0:b4f61c49c866 279 wait_ms(1);
JackB 0:b4f61c49c866 280
JackB 0:b4f61c49c866 281 err = _sync();
JackB 0:b4f61c49c866 282 if (err) {
JackB 0:b4f61c49c866 283 return err;
JackB 0:b4f61c49c866 284 }
JackB 0:b4f61c49c866 285 }
JackB 0:b4f61c49c866 286
JackB 0:b4f61c49c866 287 return 0;
JackB 0:b4f61c49c866 288 }
JackB 0:b4f61c49c866 289
JackB 0:b4f61c49c866 290 int SPIFBlockDevice::erase(bd_addr_t addr, bd_size_t size)
JackB 0:b4f61c49c866 291 {
JackB 0:b4f61c49c866 292 // Check the address and size fit onto the chip.
JackB 0:b4f61c49c866 293 MBED_ASSERT(is_valid_erase(addr, size));
JackB 0:b4f61c49c866 294
JackB 0:b4f61c49c866 295 while (size > 0) {
JackB 0:b4f61c49c866 296 int err = _wren();
JackB 0:b4f61c49c866 297 if (err) {
JackB 0:b4f61c49c866 298 return err;
JackB 0:b4f61c49c866 299 }
JackB 0:b4f61c49c866 300
JackB 0:b4f61c49c866 301 // Erase 4kbyte sectors
JackB 0:b4f61c49c866 302 // TODO support other erase sizes?
JackB 0:b4f61c49c866 303 uint32_t chunk = 4096;
JackB 0:b4f61c49c866 304 _cmdwrite(SPIF_SE, 3, 0, addr, NULL);
JackB 0:b4f61c49c866 305 addr += chunk;
JackB 0:b4f61c49c866 306 size -= chunk;
JackB 0:b4f61c49c866 307
JackB 0:b4f61c49c866 308 err = _sync();
JackB 0:b4f61c49c866 309 if (err) {
JackB 0:b4f61c49c866 310 return err;
JackB 0:b4f61c49c866 311 }
JackB 0:b4f61c49c866 312 }
JackB 0:b4f61c49c866 313
JackB 0:b4f61c49c866 314 return 0;
JackB 0:b4f61c49c866 315 }
JackB 0:b4f61c49c866 316
JackB 0:b4f61c49c866 317 bd_size_t SPIFBlockDevice::get_read_size() const
JackB 0:b4f61c49c866 318 {
JackB 0:b4f61c49c866 319 return SPIF_READ_SIZE;
JackB 0:b4f61c49c866 320 }
JackB 0:b4f61c49c866 321
JackB 0:b4f61c49c866 322 bd_size_t SPIFBlockDevice::get_program_size() const
JackB 0:b4f61c49c866 323 {
JackB 0:b4f61c49c866 324 return SPIF_PROG_SIZE;
JackB 0:b4f61c49c866 325 }
JackB 0:b4f61c49c866 326
JackB 0:b4f61c49c866 327 bd_size_t SPIFBlockDevice::get_erase_size() const
JackB 0:b4f61c49c866 328 {
JackB 0:b4f61c49c866 329 return SPIF_SE_SIZE;
JackB 0:b4f61c49c866 330 }
JackB 0:b4f61c49c866 331
JackB 0:b4f61c49c866 332 bd_size_t SPIFBlockDevice::size() const
JackB 0:b4f61c49c866 333 {
JackB 0:b4f61c49c866 334 return _size;
JackB 0:b4f61c49c866 335 }
JackB 0:b4f61c49c866 336
JackB 0:b4f61c49c866 337 int SPIFBlockDevice::get_erase_value() const
JackB 0:b4f61c49c866 338 {
JackB 0:b4f61c49c866 339 return 0xFF;
JackB 0:b4f61c49c866 340 }