TEST

Dependencies:   max32630fthr Adafruit_FeatherOLED USBDevice

Committer:
wwwarunraj
Date:
Sun Apr 19 11:19:57 2020 +0000
Revision:
4:291477e8690d
Parent:
1:f60eafbf009a
19/04

Who changed what in which revision?

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