RTC auf true

Committer:
kevman
Date:
Wed Mar 13 11:03:24 2019 +0000
Revision:
2:7aab896b1a3b
2019-03-13

Who changed what in which revision?

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