A library to read and write all 25* serial SPI flash devices from various manufacturers.

Committer:
stonie
Date:
Sun Feb 20 11:16:27 2011 +0000
Revision:
2:14c5db5e54df
Parent:
1:aa6409c599cb
minor fixes

Who changed what in which revision?

UserRevisionLine numberNew contents of line
stonie 0:d07f90d3c670 1 /* This library is based on the Ser25lcxxx library by Hendrik Lipka
stonie 0:d07f90d3c670 2 * It was adapted to flash memory chips on 19.2.2011 by Klaus Steinhammer
stonie 0:d07f90d3c670 3 * the BSD license also applies to this code - have fun.
stonie 0:d07f90d3c670 4 */
stonie 0:d07f90d3c670 5
stonie 0:d07f90d3c670 6 /*
stonie 0:d07f90d3c670 7 * Ser25lcxxx library
stonie 0:d07f90d3c670 8 * Copyright (c) 2010 Hendrik Lipka
stonie 0:d07f90d3c670 9 *
stonie 0:d07f90d3c670 10 * Permission is hereby granted, free of charge, to any person obtaining a copy
stonie 0:d07f90d3c670 11 * of this software and associated documentation files (the "Software"), to deal
stonie 0:d07f90d3c670 12 * in the Software without restriction, including without limitation the rights
stonie 0:d07f90d3c670 13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
stonie 0:d07f90d3c670 14 * copies of the Software, and to permit persons to whom the Software is
stonie 0:d07f90d3c670 15 * furnished to do so, subject to the following conditions:
stonie 0:d07f90d3c670 16 *
stonie 0:d07f90d3c670 17 * The above copyright notice and this permission notice shall be included in
stonie 0:d07f90d3c670 18 * all copies or substantial portions of the Software.
stonie 0:d07f90d3c670 19 *
stonie 0:d07f90d3c670 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
stonie 0:d07f90d3c670 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
stonie 0:d07f90d3c670 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
stonie 0:d07f90d3c670 23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
stonie 0:d07f90d3c670 24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
stonie 0:d07f90d3c670 25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
stonie 0:d07f90d3c670 26 * THE SOFTWARE.
stonie 0:d07f90d3c670 27 */
stonie 0:d07f90d3c670 28
stonie 0:d07f90d3c670 29
stonie 0:d07f90d3c670 30 #include "flash25spi.h"
stonie 0:d07f90d3c670 31 #include "wait_api.h"
stonie 0:d07f90d3c670 32
stonie 0:d07f90d3c670 33 //#define DEBUG
stonie 0:d07f90d3c670 34
stonie 0:d07f90d3c670 35 struct dataBase {
stonie 0:d07f90d3c670 36 unsigned char vendor;
stonie 0:d07f90d3c670 37 unsigned char device;
stonie 0:d07f90d3c670 38 unsigned char capacity;
stonie 0:d07f90d3c670 39 unsigned int memsize;
stonie 0:d07f90d3c670 40 unsigned int blocksize;
stonie 0:d07f90d3c670 41 unsigned int sectorsize;
stonie 0:d07f90d3c670 42 unsigned int pagesize;
stonie 0:d07f90d3c670 43 };
stonie 0:d07f90d3c670 44
stonie 0:d07f90d3c670 45 const struct dataBase devices[] = {
stonie 0:d07f90d3c670 46 // vendor, device, capacity, memsize, blocksize, sectorsize, pagesize
stonie 0:d07f90d3c670 47 { 0x1c, 0x31, 0x10, 0x10000, 0x8000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25F05 (untested)
stonie 0:d07f90d3c670 48 { 0x1c, 0x31, 0x11, 0x20000, 0x8000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25F10 (untested)
stonie 0:d07f90d3c670 49 { 0x1c, 0x31, 0x12, 0x40000, 0x10000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25F20 (untested)
stonie 0:d07f90d3c670 50 { 0x1c, 0x31, 0x13, 0x80000, 0x10000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25F40 (untested)
stonie 0:d07f90d3c670 51 { 0x1c, 0x31, 0x14, 0x100000, 0x10000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25F80 (untested)
stonie 0:d07f90d3c670 52 { 0x1c, 0x31, 0x15, 0x200000, 0x10000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25F16 (untested)
stonie 0:d07f90d3c670 53 { 0x1c, 0x30, 0x15, 0x200000, 0x10000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25Q16 (untested)
stonie 0:d07f90d3c670 54 { 0x1c, 0x31, 0x16, 0x400000, 0x10000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25F32 (untested)
stonie 0:d07f90d3c670 55 { 0x1c, 0x30, 0x16, 0x400000, 0x10000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25Q32A
stonie 0:d07f90d3c670 56 { 0x1c, 0x30, 0x17, 0x800000, 0x10000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25Q64 (untested)
stonie 0:d07f90d3c670 57 { 0x1c, 0x30, 0x18, 0x1000000, 0x10000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25Q128 (untested)
stonie 0:d07f90d3c670 58
stonie 0:d07f90d3c670 59 { 0x20, 0x20, 0x10, 0x10000, 0x8000, 0, 0x100}, // Manufacturer: Numonyx, Device: M25P05-A (untested)
stonie 0:d07f90d3c670 60 { 0x20, 0x20, 0x16, 0x400000, 0x10000, 0, 0x100}, // Manufacturer: Numonyx, Device: M25P32 (untested)
stonie 0:d07f90d3c670 61 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // end of table
stonie 0:d07f90d3c670 62 };
stonie 0:d07f90d3c670 63
stonie 0:d07f90d3c670 64
stonie 0:d07f90d3c670 65 #define HIGH(x) ((x&0xff0000)>>16)
stonie 0:d07f90d3c670 66 #define MID(x) ((x&0xff00)>>8)
stonie 0:d07f90d3c670 67 #define LOW(x) (x&0xff)
stonie 0:d07f90d3c670 68
stonie 1:aa6409c599cb 69 flash25spi::flash25spi(SPI *spi, PinName enable) {
stonie 0:d07f90d3c670 70 unsigned char chipid[3];
stonie 0:d07f90d3c670 71 unsigned int i = 0;
stonie 0:d07f90d3c670 72 _spi=spi;
stonie 0:d07f90d3c670 73 _enable=new DigitalOut(enable);
stonie 0:d07f90d3c670 74 _enable->write(1);
stonie 0:d07f90d3c670 75
stonie 0:d07f90d3c670 76 wait_us(1000);
stonie 0:d07f90d3c670 77
stonie 0:d07f90d3c670 78 _enable->write(0);
stonie 0:d07f90d3c670 79 wait_us(1);
stonie 0:d07f90d3c670 80 // send address
stonie 0:d07f90d3c670 81 _spi->write(0x9f);
stonie 0:d07f90d3c670 82 chipid[0] = _spi->write(0); // get vendor ID
stonie 0:d07f90d3c670 83 chipid[1] = _spi->write(0); // get device ID
stonie 0:d07f90d3c670 84 chipid[2] = _spi->write(0); // get capacity
stonie 0:d07f90d3c670 85 wait_us(1);
stonie 0:d07f90d3c670 86 _enable->write(1);
stonie 0:d07f90d3c670 87
stonie 0:d07f90d3c670 88 _size = 0;
stonie 0:d07f90d3c670 89
stonie 0:d07f90d3c670 90 #ifdef DEBUG
stonie 0:d07f90d3c670 91 printf ("got flash ids: %x, %x, %x\n", chipid[0], chipid[1], chipid[2]);
stonie 0:d07f90d3c670 92 #endif
stonie 0:d07f90d3c670 93
stonie 0:d07f90d3c670 94 while (_size == 0) {
stonie 0:d07f90d3c670 95 #ifdef DEBUG
stonie 0:d07f90d3c670 96 printf ("checking: %x, %x, %x\n", devices[i].vendor, devices[i].device, devices[i].capacity);
stonie 0:d07f90d3c670 97 #endif
stonie 0:d07f90d3c670 98 if (devices[i].vendor == 0) {
stonie 0:d07f90d3c670 99 printf("flash device not found\n");
stonie 0:d07f90d3c670 100 return;
stonie 0:d07f90d3c670 101 }
stonie 0:d07f90d3c670 102 if ((chipid[0] == devices[i].vendor) &&
stonie 0:d07f90d3c670 103 (chipid[1] == devices[i].device) &&
stonie 0:d07f90d3c670 104 (chipid[2] == devices[i].capacity)) {
stonie 0:d07f90d3c670 105 _size=devices[i].memsize;
stonie 0:d07f90d3c670 106 _blockSize=devices[i].blocksize;
stonie 0:d07f90d3c670 107 _sectorSize=devices[i].sectorsize;
stonie 0:d07f90d3c670 108 _pageSize=devices[i].pagesize;
stonie 0:d07f90d3c670 109 #ifdef DEBUG
stonie 0:d07f90d3c670 110 printf("device found: %x - %x, %x, %x, %x\n",i, _size, _blockSize, _sectorSize, _pageSize);
stonie 0:d07f90d3c670 111 #endif
stonie 0:d07f90d3c670 112 }
stonie 0:d07f90d3c670 113 else
stonie 0:d07f90d3c670 114 i++;
stonie 0:d07f90d3c670 115 }
stonie 0:d07f90d3c670 116 return;
stonie 0:d07f90d3c670 117 }
stonie 0:d07f90d3c670 118
stonie 0:d07f90d3c670 119 flash25spi::~flash25spi() {
stonie 0:d07f90d3c670 120 delete _enable;
stonie 0:d07f90d3c670 121 }
stonie 0:d07f90d3c670 122
stonie 0:d07f90d3c670 123 char* flash25spi::read(unsigned int startAdr, unsigned int len) {
stonie 0:d07f90d3c670 124 // assertion
stonie 0:d07f90d3c670 125 if (startAdr+len>_size)
stonie 0:d07f90d3c670 126 return NULL;
stonie 0:d07f90d3c670 127 char* ret=(char*)malloc(len);
stonie 0:d07f90d3c670 128 if (!len) return NULL;
stonie 0:d07f90d3c670 129
stonie 0:d07f90d3c670 130 _enable->write(0);
stonie 0:d07f90d3c670 131 wait_us(1);
stonie 0:d07f90d3c670 132 // send address
stonie 0:d07f90d3c670 133 _spi->write(0x03);
stonie 0:d07f90d3c670 134 _spi->write(HIGH(startAdr));
stonie 0:d07f90d3c670 135 _spi->write(MID(startAdr));
stonie 0:d07f90d3c670 136 _spi->write(LOW(startAdr));
stonie 0:d07f90d3c670 137
stonie 0:d07f90d3c670 138 // read data into buffer
stonie 0:d07f90d3c670 139 for (unsigned int i=0;i<len;i++) {
stonie 0:d07f90d3c670 140 ret[i]=_spi->write(0);
stonie 0:d07f90d3c670 141 }
stonie 0:d07f90d3c670 142 wait_us(1);
stonie 0:d07f90d3c670 143 _enable->write(1);
stonie 0:d07f90d3c670 144 return ret;
stonie 0:d07f90d3c670 145 }
stonie 0:d07f90d3c670 146
stonie 0:d07f90d3c670 147 bool flash25spi::write(unsigned int startAdr, unsigned int len, const char* data) {
stonie 0:d07f90d3c670 148 if (startAdr+len>_size)
stonie 2:14c5db5e54df 149 return false;
stonie 0:d07f90d3c670 150
stonie 0:d07f90d3c670 151 unsigned int ofs=0;
stonie 0:d07f90d3c670 152 while (ofs<len) {
stonie 0:d07f90d3c670 153 // calculate amount of data to write into current page
stonie 0:d07f90d3c670 154 int pageLen=_pageSize-((startAdr+ofs)%_pageSize);
stonie 0:d07f90d3c670 155 if (ofs+pageLen>len)
stonie 0:d07f90d3c670 156 pageLen=len-ofs;
stonie 0:d07f90d3c670 157 // write single page
stonie 0:d07f90d3c670 158 bool b=writePage(startAdr+ofs,pageLen,data+ofs);
stonie 0:d07f90d3c670 159 if (!b)
stonie 0:d07f90d3c670 160 return false;
stonie 0:d07f90d3c670 161 // and switch to next page
stonie 0:d07f90d3c670 162 ofs+=pageLen;
stonie 0:d07f90d3c670 163 }
stonie 0:d07f90d3c670 164 return true;
stonie 0:d07f90d3c670 165 }
stonie 0:d07f90d3c670 166
stonie 0:d07f90d3c670 167 bool flash25spi::writePage(unsigned int startAdr, unsigned int len, const char* data) {
stonie 0:d07f90d3c670 168 enableWrite();
stonie 0:d07f90d3c670 169
stonie 0:d07f90d3c670 170 _enable->write(0);
stonie 0:d07f90d3c670 171 wait_us(1);
stonie 0:d07f90d3c670 172
stonie 0:d07f90d3c670 173 _spi->write(0x02);
stonie 0:d07f90d3c670 174 _spi->write(HIGH(startAdr));
stonie 0:d07f90d3c670 175 _spi->write(MID(startAdr));
stonie 0:d07f90d3c670 176 _spi->write(LOW(startAdr));
stonie 0:d07f90d3c670 177
stonie 0:d07f90d3c670 178 // do real write
stonie 0:d07f90d3c670 179 for (unsigned int i=0;i<len;i++) {
stonie 0:d07f90d3c670 180 _spi->write(data[i]);
stonie 0:d07f90d3c670 181 }
stonie 0:d07f90d3c670 182 wait_us(1);
stonie 0:d07f90d3c670 183 // disable to start physical write
stonie 0:d07f90d3c670 184 _enable->write(1);
stonie 0:d07f90d3c670 185
stonie 0:d07f90d3c670 186 waitForWrite();
stonie 0:d07f90d3c670 187
stonie 0:d07f90d3c670 188 return true;
stonie 0:d07f90d3c670 189 }
stonie 0:d07f90d3c670 190
stonie 0:d07f90d3c670 191 void flash25spi::clearSector(unsigned int addr) {
stonie 0:d07f90d3c670 192 if (_sectorSize == 0) {
stonie 0:d07f90d3c670 193 clearBlock(addr);
stonie 0:d07f90d3c670 194 return;
stonie 0:d07f90d3c670 195 }
stonie 0:d07f90d3c670 196
stonie 0:d07f90d3c670 197 addr &= ~(_sectorSize-1);
stonie 0:d07f90d3c670 198
stonie 0:d07f90d3c670 199 enableWrite();
stonie 0:d07f90d3c670 200 _enable->write(0);
stonie 0:d07f90d3c670 201 wait_us(1);
stonie 0:d07f90d3c670 202 _spi->write(0x20);
stonie 0:d07f90d3c670 203 _spi->write(HIGH(addr));
stonie 0:d07f90d3c670 204 _spi->write(MID(addr));
stonie 0:d07f90d3c670 205 _spi->write(LOW(addr));
stonie 0:d07f90d3c670 206 wait_us(1);
stonie 0:d07f90d3c670 207 _enable->write(1);
stonie 0:d07f90d3c670 208 waitForWrite();
stonie 0:d07f90d3c670 209 }
stonie 0:d07f90d3c670 210
stonie 0:d07f90d3c670 211 void flash25spi::clearBlock(unsigned int addr) {
stonie 0:d07f90d3c670 212 addr &= ~(_blockSize-1);
stonie 0:d07f90d3c670 213
stonie 0:d07f90d3c670 214 enableWrite();
stonie 0:d07f90d3c670 215 _enable->write(0);
stonie 0:d07f90d3c670 216 wait_us(1);
stonie 0:d07f90d3c670 217 _spi->write(0xd8);
stonie 0:d07f90d3c670 218 _spi->write(HIGH(addr));
stonie 0:d07f90d3c670 219 _spi->write(MID(addr));
stonie 0:d07f90d3c670 220 _spi->write(LOW(addr));
stonie 0:d07f90d3c670 221 wait_us(1);
stonie 0:d07f90d3c670 222 _enable->write(1);
stonie 0:d07f90d3c670 223 waitForWrite();
stonie 0:d07f90d3c670 224 }
stonie 0:d07f90d3c670 225
stonie 0:d07f90d3c670 226 void flash25spi::clearMem() {
stonie 0:d07f90d3c670 227 enableWrite();
stonie 0:d07f90d3c670 228 _enable->write(0);
stonie 0:d07f90d3c670 229 wait_us(1);
stonie 0:d07f90d3c670 230 _spi->write(0xc7);
stonie 0:d07f90d3c670 231 wait_us(1);
stonie 0:d07f90d3c670 232 _enable->write(1);
stonie 0:d07f90d3c670 233 waitForWrite();
stonie 0:d07f90d3c670 234 }
stonie 0:d07f90d3c670 235
stonie 0:d07f90d3c670 236 int flash25spi::readStatus() {
stonie 0:d07f90d3c670 237 _enable->write(0);
stonie 0:d07f90d3c670 238 wait_us(1);
stonie 0:d07f90d3c670 239 _spi->write(0x5);
stonie 0:d07f90d3c670 240 int status=_spi->write(0x00);
stonie 0:d07f90d3c670 241 wait_us(1);
stonie 0:d07f90d3c670 242 _enable->write(1);
stonie 0:d07f90d3c670 243 return status;
stonie 0:d07f90d3c670 244 }
stonie 0:d07f90d3c670 245
stonie 0:d07f90d3c670 246 void flash25spi::waitForWrite() {
stonie 0:d07f90d3c670 247 while (true) {
stonie 0:d07f90d3c670 248 if (0==readStatus()&1)
stonie 0:d07f90d3c670 249 break;
stonie 0:d07f90d3c670 250 wait_us(10);
stonie 0:d07f90d3c670 251 }
stonie 0:d07f90d3c670 252 }
stonie 0:d07f90d3c670 253
stonie 0:d07f90d3c670 254 void flash25spi::enableWrite()
stonie 0:d07f90d3c670 255 {
stonie 0:d07f90d3c670 256 _enable->write(0);
stonie 0:d07f90d3c670 257 wait_us(1);
stonie 0:d07f90d3c670 258 _spi->write(0x06);
stonie 0:d07f90d3c670 259 wait_us(1);
stonie 0:d07f90d3c670 260 _enable->write(1);
stonie 0:d07f90d3c670 261 }