Driver for SST 64Mbit flash (8Mbyte) model 25VF064C including higher level methods for rewrite and buffered read/write to help optimize I/O. Can also work with other 25 series flash and eeprom devices, requiring minor revisions for their capabilities.
SST25VF064C.cpp@2:33d8a5ea4a80, 2012-04-12 (annotated)
- Committer:
- davervw
- Date:
- Thu Apr 12 14:16:37 2012 +0000
- Revision:
- 2:33d8a5ea4a80
- Parent:
- 0:332d4b991d16
Cosmetic change. Changing "eeprom" to "flash" for accuracy.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
davervw | 0:332d4b991d16 | 1 | /////////////////////////////////////////////////////////////////////////////// |
davervw | 2:33d8a5ea4a80 | 2 | // SST25VF064C.cpp - Flash driver |
davervw | 0:332d4b991d16 | 3 | // |
davervw | 0:332d4b991d16 | 4 | // COPYRIGHT (c) 2012 by David Van Wagner |
davervw | 0:332d4b991d16 | 5 | // |
davervw | 0:332d4b991d16 | 6 | // dave@vanwagner.org |
davervw | 0:332d4b991d16 | 7 | // http://techwithdave.blogspot.com |
davervw | 0:332d4b991d16 | 8 | // |
davervw | 0:332d4b991d16 | 9 | // License: Creative Commons Attribution-ShareAlike 3.0 Unported License |
davervw | 0:332d4b991d16 | 10 | // http://creativecommons.org/licenses/by-sa/3.0/ |
davervw | 0:332d4b991d16 | 11 | /////////////////////////////////////////////////////////////////////////////// |
davervw | 0:332d4b991d16 | 12 | |
davervw | 0:332d4b991d16 | 13 | #include "SST25VF064C.h" |
davervw | 0:332d4b991d16 | 14 | //#include <assert.h> |
davervw | 0:332d4b991d16 | 15 | |
davervw | 0:332d4b991d16 | 16 | SST25VF064C::uint8 SST25VF064C::SID_buffer[SID_LEN]; |
davervw | 0:332d4b991d16 | 17 | SST25VF064C::uint8 SST25VF064C::sector_buffer[SECTOR_LEN]; |
davervw | 0:332d4b991d16 | 18 | SST25VF064C::int32 SST25VF064C::buffered_addr; |
davervw | 0:332d4b991d16 | 19 | bool SST25VF064C::buffered_erased; |
davervw | 0:332d4b991d16 | 20 | |
davervw | 0:332d4b991d16 | 21 | SST25VF064C::SST25VF064C(PinName mosi, PinName miso, PinName sclk, PinName cs, int frequency) |
davervw | 0:332d4b991d16 | 22 | { |
davervw | 0:332d4b991d16 | 23 | #ifdef SPIDEBUG |
davervw | 0:332d4b991d16 | 24 | this->cs = new CSDebug(cs); |
davervw | 0:332d4b991d16 | 25 | #else |
davervw | 0:332d4b991d16 | 26 | this->cs = new DigitalOut(cs); |
davervw | 0:332d4b991d16 | 27 | #endif |
davervw | 0:332d4b991d16 | 28 | this->cs->write(true); |
davervw | 0:332d4b991d16 | 29 | this->frequency = frequency; |
davervw | 0:332d4b991d16 | 30 | #ifdef SPIDEBUG |
davervw | 0:332d4b991d16 | 31 | spi = new SPIDebug(mosi, miso, sclk); |
davervw | 0:332d4b991d16 | 32 | #else |
davervw | 0:332d4b991d16 | 33 | spi = new SPI(mosi, miso, sclk); |
davervw | 0:332d4b991d16 | 34 | #endif |
davervw | 0:332d4b991d16 | 35 | spi->format(8, 0); |
davervw | 0:332d4b991d16 | 36 | spi->frequency(frequency); |
davervw | 0:332d4b991d16 | 37 | buffered_addr = -1; |
davervw | 0:332d4b991d16 | 38 | buffered_erased = false; |
davervw | 0:332d4b991d16 | 39 | //assert(Id() == 0x4bbf); |
davervw | 0:332d4b991d16 | 40 | //assert(JEDECId() == 0xbf254b); |
davervw | 0:332d4b991d16 | 41 | } |
davervw | 0:332d4b991d16 | 42 | |
davervw | 0:332d4b991d16 | 43 | SST25VF064C::~SST25VF064C() |
davervw | 0:332d4b991d16 | 44 | { |
davervw | 0:332d4b991d16 | 45 | delete spi; |
davervw | 0:332d4b991d16 | 46 | delete cs; |
davervw | 0:332d4b991d16 | 47 | } |
davervw | 0:332d4b991d16 | 48 | |
davervw | 0:332d4b991d16 | 49 | SST25VF064C::uint16 SST25VF064C::Id() |
davervw | 0:332d4b991d16 | 50 | { |
davervw | 0:332d4b991d16 | 51 | cs->write(0); |
davervw | 0:332d4b991d16 | 52 | spi->write(0xab); |
davervw | 0:332d4b991d16 | 53 | spi->write(0); |
davervw | 0:332d4b991d16 | 54 | spi->write(0); |
davervw | 0:332d4b991d16 | 55 | spi->write(0); |
davervw | 0:332d4b991d16 | 56 | unsigned id = (spi->write(0) << 8) | spi->write(0); |
davervw | 0:332d4b991d16 | 57 | cs->write(1); |
davervw | 0:332d4b991d16 | 58 | return id; |
davervw | 0:332d4b991d16 | 59 | } |
davervw | 0:332d4b991d16 | 60 | |
davervw | 0:332d4b991d16 | 61 | SST25VF064C::uint32 SST25VF064C::JEDECId() |
davervw | 0:332d4b991d16 | 62 | { |
davervw | 0:332d4b991d16 | 63 | cs->write(0); |
davervw | 0:332d4b991d16 | 64 | spi->write(0x9f); |
davervw | 0:332d4b991d16 | 65 | unsigned id = (spi->write(0) << 16) | (spi->write(0) << 8) | spi->write(0); |
davervw | 0:332d4b991d16 | 66 | cs->write(1); |
davervw | 0:332d4b991d16 | 67 | return id; |
davervw | 0:332d4b991d16 | 68 | } |
davervw | 0:332d4b991d16 | 69 | |
davervw | 0:332d4b991d16 | 70 | SST25VF064C::uint8* SST25VF064C::SID() |
davervw | 0:332d4b991d16 | 71 | { |
davervw | 0:332d4b991d16 | 72 | cs->write(0); |
davervw | 0:332d4b991d16 | 73 | spi->write(0x88); |
davervw | 0:332d4b991d16 | 74 | spi->write(0); // address |
davervw | 0:332d4b991d16 | 75 | spi->write(0); // dummy |
davervw | 0:332d4b991d16 | 76 | for (int i=0; i<SID_LEN; ++i) |
davervw | 0:332d4b991d16 | 77 | SID_buffer[i] = spi->write(0); |
davervw | 0:332d4b991d16 | 78 | cs->write(1); |
davervw | 0:332d4b991d16 | 79 | return SID_buffer; |
davervw | 0:332d4b991d16 | 80 | } |
davervw | 0:332d4b991d16 | 81 | |
davervw | 0:332d4b991d16 | 82 | // Read Status Register |
davervw | 0:332d4b991d16 | 83 | // bit 0 BUSY 1=Write in progress |
davervw | 0:332d4b991d16 | 84 | // bit 1 WEL 1=Write Enabled |
davervw | 0:332d4b991d16 | 85 | // bit 2 BP0 block write protection |
davervw | 0:332d4b991d16 | 86 | // bit 3 BP1 block write protection |
davervw | 0:332d4b991d16 | 87 | // bit 4 BP2 block write protection |
davervw | 0:332d4b991d16 | 88 | // bit 5 BP3 block write protection |
davervw | 0:332d4b991d16 | 89 | // bit 6 SEC 1=Security ID space locked |
davervw | 0:332d4b991d16 | 90 | // bit 7 BPL 1=BP0..BP3 are read-only, 0=r/w |
davervw | 0:332d4b991d16 | 91 | SST25VF064C::uint8 SST25VF064C::RDSR() |
davervw | 0:332d4b991d16 | 92 | { |
davervw | 0:332d4b991d16 | 93 | cs->write(0); |
davervw | 0:332d4b991d16 | 94 | spi->write(0x05); |
davervw | 0:332d4b991d16 | 95 | uint8 status = spi->write(0); |
davervw | 0:332d4b991d16 | 96 | cs->write(1); |
davervw | 0:332d4b991d16 | 97 | return status; |
davervw | 0:332d4b991d16 | 98 | } |
davervw | 0:332d4b991d16 | 99 | |
davervw | 0:332d4b991d16 | 100 | // Enable Write Status Register |
davervw | 0:332d4b991d16 | 101 | void SST25VF064C::EWSR() |
davervw | 0:332d4b991d16 | 102 | { |
davervw | 0:332d4b991d16 | 103 | cs->write(0); |
davervw | 0:332d4b991d16 | 104 | spi->write(0x50); |
davervw | 0:332d4b991d16 | 105 | cs->write(1); |
davervw | 0:332d4b991d16 | 106 | } |
davervw | 0:332d4b991d16 | 107 | |
davervw | 0:332d4b991d16 | 108 | // Write Status Register |
davervw | 0:332d4b991d16 | 109 | void SST25VF064C::WRSR(SST25VF064C::uint8 status) |
davervw | 0:332d4b991d16 | 110 | { |
davervw | 0:332d4b991d16 | 111 | cs->write(0); |
davervw | 0:332d4b991d16 | 112 | spi->write(0x01); |
davervw | 0:332d4b991d16 | 113 | spi->write(status); |
davervw | 0:332d4b991d16 | 114 | cs->write(1); |
davervw | 0:332d4b991d16 | 115 | } |
davervw | 0:332d4b991d16 | 116 | |
davervw | 0:332d4b991d16 | 117 | // Write Enable |
davervw | 0:332d4b991d16 | 118 | void SST25VF064C::WREN() |
davervw | 0:332d4b991d16 | 119 | { |
davervw | 0:332d4b991d16 | 120 | cs->write(0); |
davervw | 0:332d4b991d16 | 121 | spi->write(0x06); |
davervw | 0:332d4b991d16 | 122 | cs->write(1); |
davervw | 0:332d4b991d16 | 123 | } |
davervw | 0:332d4b991d16 | 124 | |
davervw | 0:332d4b991d16 | 125 | // Write Disable |
davervw | 0:332d4b991d16 | 126 | void SST25VF064C::WRDI() |
davervw | 0:332d4b991d16 | 127 | { |
davervw | 0:332d4b991d16 | 128 | cs->write(0); |
davervw | 0:332d4b991d16 | 129 | spi->write(0x04); |
davervw | 0:332d4b991d16 | 130 | cs->write(1); |
davervw | 0:332d4b991d16 | 131 | } |
davervw | 0:332d4b991d16 | 132 | |
davervw | 0:332d4b991d16 | 133 | bool SST25VF064C::BUSY() |
davervw | 0:332d4b991d16 | 134 | { |
davervw | 0:332d4b991d16 | 135 | return (RDSR() & 0x01) != 0; |
davervw | 0:332d4b991d16 | 136 | } |
davervw | 0:332d4b991d16 | 137 | |
davervw | 0:332d4b991d16 | 138 | bool SST25VF064C::WEL() |
davervw | 0:332d4b991d16 | 139 | { |
davervw | 0:332d4b991d16 | 140 | return (RDSR() & 0x02) != 0; |
davervw | 0:332d4b991d16 | 141 | } |
davervw | 0:332d4b991d16 | 142 | |
davervw | 0:332d4b991d16 | 143 | SST25VF064C::uint8 SST25VF064C::BP() |
davervw | 0:332d4b991d16 | 144 | { |
davervw | 0:332d4b991d16 | 145 | return (RDSR() >> 2) & 0xF; |
davervw | 0:332d4b991d16 | 146 | } |
davervw | 0:332d4b991d16 | 147 | |
davervw | 0:332d4b991d16 | 148 | bool SST25VF064C::SEC() |
davervw | 0:332d4b991d16 | 149 | { |
davervw | 0:332d4b991d16 | 150 | return (RDSR() & 0x40) != 0; |
davervw | 0:332d4b991d16 | 151 | } |
davervw | 0:332d4b991d16 | 152 | |
davervw | 0:332d4b991d16 | 153 | bool SST25VF064C::BPL() |
davervw | 0:332d4b991d16 | 154 | { |
davervw | 0:332d4b991d16 | 155 | return (RDSR() & 0x80) != 0; |
davervw | 0:332d4b991d16 | 156 | } |
davervw | 0:332d4b991d16 | 157 | |
davervw | 0:332d4b991d16 | 158 | void SST25VF064C::wait_while_busy() |
davervw | 0:332d4b991d16 | 159 | { |
davervw | 0:332d4b991d16 | 160 | while (BUSY()) |
davervw | 0:332d4b991d16 | 161 | ; |
davervw | 0:332d4b991d16 | 162 | } |
davervw | 0:332d4b991d16 | 163 | |
davervw | 0:332d4b991d16 | 164 | SST25VF064C::uint8 SST25VF064C::read(SST25VF064C::int32 addr) |
davervw | 0:332d4b991d16 | 165 | { |
davervw | 0:332d4b991d16 | 166 | cs->write(0); |
davervw | 0:332d4b991d16 | 167 | spi->write(0x03); |
davervw | 0:332d4b991d16 | 168 | spi->write((addr >> 16) & 0xff); |
davervw | 0:332d4b991d16 | 169 | spi->write((addr >> 8) & 0xff); |
davervw | 0:332d4b991d16 | 170 | spi->write(addr & 0xff); |
davervw | 0:332d4b991d16 | 171 | uint8 data = spi->write(0); |
davervw | 0:332d4b991d16 | 172 | cs->write(1); |
davervw | 0:332d4b991d16 | 173 | return data; |
davervw | 0:332d4b991d16 | 174 | } |
davervw | 0:332d4b991d16 | 175 | |
davervw | 0:332d4b991d16 | 176 | bool SST25VF064C::read(SST25VF064C::int32 addr, SST25VF064C::uint8* dst, SST25VF064C::int32 len) |
davervw | 0:332d4b991d16 | 177 | { |
davervw | 0:332d4b991d16 | 178 | if (addr < 0 || addr >= MAX_ADDR || dst == 0 || len < 1 || addr+len > MAX_ADDR) |
davervw | 0:332d4b991d16 | 179 | return false; |
davervw | 0:332d4b991d16 | 180 | |
davervw | 0:332d4b991d16 | 181 | cs->write(0); |
davervw | 0:332d4b991d16 | 182 | spi->write(0x03); |
davervw | 0:332d4b991d16 | 183 | spi->write((addr >> 16) & 0xff); |
davervw | 0:332d4b991d16 | 184 | spi->write((addr >> 8) & 0xff); |
davervw | 0:332d4b991d16 | 185 | spi->write(addr & 0xff); |
davervw | 0:332d4b991d16 | 186 | for (int32 i=0; i<len; ++i) |
davervw | 0:332d4b991d16 | 187 | dst[i] = spi->write(0); |
davervw | 0:332d4b991d16 | 188 | cs->write(1); |
davervw | 0:332d4b991d16 | 189 | |
davervw | 0:332d4b991d16 | 190 | return true; |
davervw | 0:332d4b991d16 | 191 | } |
davervw | 0:332d4b991d16 | 192 | |
davervw | 0:332d4b991d16 | 193 | void SST25VF064C::hsread(SST25VF064C::int32 addr, SST25VF064C::uint8* dst, SST25VF064C::int32 len, int frequency) |
davervw | 0:332d4b991d16 | 194 | { |
davervw | 0:332d4b991d16 | 195 | int save_frequency = this->frequency; |
davervw | 0:332d4b991d16 | 196 | spi->frequency(frequency); |
davervw | 0:332d4b991d16 | 197 | cs->write(0); |
davervw | 0:332d4b991d16 | 198 | spi->write(0x0B); |
davervw | 0:332d4b991d16 | 199 | spi->write((addr >> 16) & 0xff); |
davervw | 0:332d4b991d16 | 200 | spi->write((addr >> 8) & 0xff); |
davervw | 0:332d4b991d16 | 201 | spi->write(addr & 0xff); |
davervw | 0:332d4b991d16 | 202 | spi->write(0); // dummy |
davervw | 0:332d4b991d16 | 203 | for (int32 i=0; i<len; ++i) |
davervw | 0:332d4b991d16 | 204 | dst[i] = spi->write(0); |
davervw | 0:332d4b991d16 | 205 | cs->write(1); |
davervw | 0:332d4b991d16 | 206 | spi->frequency(save_frequency); |
davervw | 0:332d4b991d16 | 207 | } |
davervw | 0:332d4b991d16 | 208 | |
davervw | 0:332d4b991d16 | 209 | void SST25VF064C::sector_erase_4k(SST25VF064C::int32 addr) |
davervw | 0:332d4b991d16 | 210 | { |
davervw | 0:332d4b991d16 | 211 | cs->write(0); |
davervw | 0:332d4b991d16 | 212 | spi->write(0x20); |
davervw | 0:332d4b991d16 | 213 | spi->write((uint8)(addr >> 16)); |
davervw | 0:332d4b991d16 | 214 | spi->write((uint8)(addr >> 8)); |
davervw | 0:332d4b991d16 | 215 | spi->write((uint8)addr); |
davervw | 0:332d4b991d16 | 216 | cs->write(1); |
davervw | 0:332d4b991d16 | 217 | wait_while_busy(); |
davervw | 0:332d4b991d16 | 218 | } |
davervw | 0:332d4b991d16 | 219 | |
davervw | 0:332d4b991d16 | 220 | void SST25VF064C::block_erase_32k(SST25VF064C::int32 addr) |
davervw | 0:332d4b991d16 | 221 | { |
davervw | 0:332d4b991d16 | 222 | cs->write(0); |
davervw | 0:332d4b991d16 | 223 | spi->write(0x52); |
davervw | 0:332d4b991d16 | 224 | spi->write((uint8)(addr >> 16)); |
davervw | 0:332d4b991d16 | 225 | spi->write((uint8)(addr >> 8)); |
davervw | 0:332d4b991d16 | 226 | spi->write((uint8)addr); |
davervw | 0:332d4b991d16 | 227 | cs->write(1); |
davervw | 0:332d4b991d16 | 228 | wait_while_busy(); |
davervw | 0:332d4b991d16 | 229 | } |
davervw | 0:332d4b991d16 | 230 | |
davervw | 0:332d4b991d16 | 231 | void SST25VF064C::block_erase_64k(SST25VF064C::int32 addr) |
davervw | 0:332d4b991d16 | 232 | { |
davervw | 0:332d4b991d16 | 233 | cs->write(0); |
davervw | 0:332d4b991d16 | 234 | spi->write(0xd8); |
davervw | 0:332d4b991d16 | 235 | spi->write((uint8)(addr >> 16)); |
davervw | 0:332d4b991d16 | 236 | spi->write((uint8)(addr >> 8)); |
davervw | 0:332d4b991d16 | 237 | spi->write((uint8)addr); |
davervw | 0:332d4b991d16 | 238 | cs->write(1); |
davervw | 0:332d4b991d16 | 239 | wait_while_busy(); |
davervw | 0:332d4b991d16 | 240 | } |
davervw | 0:332d4b991d16 | 241 | |
davervw | 0:332d4b991d16 | 242 | void SST25VF064C::chip_erase() |
davervw | 0:332d4b991d16 | 243 | { |
davervw | 0:332d4b991d16 | 244 | cs->write(0); |
davervw | 0:332d4b991d16 | 245 | spi->write(0x60); |
davervw | 0:332d4b991d16 | 246 | cs->write(1); |
davervw | 0:332d4b991d16 | 247 | wait_while_busy(); |
davervw | 0:332d4b991d16 | 248 | } |
davervw | 0:332d4b991d16 | 249 | |
davervw | 0:332d4b991d16 | 250 | bool SST25VF064C::page_program(SST25VF064C::int32 addr, SST25VF064C::uint8* write_buffer, short len) |
davervw | 0:332d4b991d16 | 251 | { |
davervw | 0:332d4b991d16 | 252 | // no point in writing FF as an empty sector already has those |
davervw | 0:332d4b991d16 | 253 | // (and if not empty, write won't succeed) |
davervw | 0:332d4b991d16 | 254 | bool skipped = false; |
davervw | 0:332d4b991d16 | 255 | while (len > 0 && *write_buffer == 0xFF) |
davervw | 0:332d4b991d16 | 256 | { |
davervw | 0:332d4b991d16 | 257 | ++write_buffer; |
davervw | 0:332d4b991d16 | 258 | --len; |
davervw | 0:332d4b991d16 | 259 | ++addr; |
davervw | 0:332d4b991d16 | 260 | skipped = true; |
davervw | 0:332d4b991d16 | 261 | } |
davervw | 0:332d4b991d16 | 262 | if (len == 0 && skipped) |
davervw | 0:332d4b991d16 | 263 | return true; // special case when succeeds when nothing to do |
davervw | 0:332d4b991d16 | 264 | |
davervw | 0:332d4b991d16 | 265 | if (len < 1 || len > 256) |
davervw | 0:332d4b991d16 | 266 | return false; |
davervw | 0:332d4b991d16 | 267 | |
davervw | 0:332d4b991d16 | 268 | // write enable |
davervw | 0:332d4b991d16 | 269 | WREN(); |
davervw | 0:332d4b991d16 | 270 | |
davervw | 0:332d4b991d16 | 271 | cs->write(0); |
davervw | 0:332d4b991d16 | 272 | spi->write(0x02); |
davervw | 0:332d4b991d16 | 273 | spi->write((uint8)(addr >> 16)); |
davervw | 0:332d4b991d16 | 274 | spi->write((uint8)(addr >> 8)); |
davervw | 0:332d4b991d16 | 275 | spi->write((uint8)addr); |
davervw | 0:332d4b991d16 | 276 | for (short i=0; i<len; ++i) |
davervw | 0:332d4b991d16 | 277 | spi->write(write_buffer[i]); |
davervw | 0:332d4b991d16 | 278 | cs->write(1); |
davervw | 0:332d4b991d16 | 279 | wait_while_busy(); |
davervw | 0:332d4b991d16 | 280 | |
davervw | 0:332d4b991d16 | 281 | return true; |
davervw | 0:332d4b991d16 | 282 | } |
davervw | 0:332d4b991d16 | 283 | |
davervw | 0:332d4b991d16 | 284 | bool SST25VF064C::write(SST25VF064C::int32 addr, SST25VF064C::uint8* write_buffer, SST25VF064C::int32 len) |
davervw | 0:332d4b991d16 | 285 | { |
davervw | 0:332d4b991d16 | 286 | if (len < 0 || addr < 0 || addr > MAX_ADDR || (addr+len > MAX_ADDR) || (addr+len < 0)) |
davervw | 0:332d4b991d16 | 287 | return false; |
davervw | 0:332d4b991d16 | 288 | |
davervw | 0:332d4b991d16 | 289 | if (len == 0) |
davervw | 0:332d4b991d16 | 290 | return true; // done! |
davervw | 0:332d4b991d16 | 291 | |
davervw | 0:332d4b991d16 | 292 | // calculate first page size based on address and length |
davervw | 0:332d4b991d16 | 293 | int32 page_len = PAGE_LEN-(addr & (PAGE_LEN-1)); // remaining space in page |
davervw | 0:332d4b991d16 | 294 | |
davervw | 0:332d4b991d16 | 295 | while (len > 0) |
davervw | 0:332d4b991d16 | 296 | { |
davervw | 0:332d4b991d16 | 297 | if (page_len > len) |
davervw | 0:332d4b991d16 | 298 | page_len = len; |
davervw | 0:332d4b991d16 | 299 | |
davervw | 0:332d4b991d16 | 300 | page_program(addr, write_buffer, page_len); |
davervw | 0:332d4b991d16 | 301 | |
davervw | 0:332d4b991d16 | 302 | addr += page_len; |
davervw | 0:332d4b991d16 | 303 | write_buffer += page_len; |
davervw | 0:332d4b991d16 | 304 | len -= page_len; |
davervw | 0:332d4b991d16 | 305 | page_len = PAGE_LEN; |
davervw | 0:332d4b991d16 | 306 | } |
davervw | 0:332d4b991d16 | 307 | |
davervw | 0:332d4b991d16 | 308 | return true; |
davervw | 0:332d4b991d16 | 309 | } |
davervw | 0:332d4b991d16 | 310 | |
davervw | 0:332d4b991d16 | 311 | bool SST25VF064C::rewrite(SST25VF064C::int32 addr, SST25VF064C::uint8* write_buffer, SST25VF064C::int32 len) |
davervw | 0:332d4b991d16 | 312 | { |
davervw | 0:332d4b991d16 | 313 | // validate parameters |
davervw | 0:332d4b991d16 | 314 | if (len < 0 || addr < 0 || addr > MAX_ADDR || (addr+len > MAX_ADDR) || (addr+len < 0)) |
davervw | 0:332d4b991d16 | 315 | return false; |
davervw | 0:332d4b991d16 | 316 | |
davervw | 0:332d4b991d16 | 317 | // are we done before we've started? |
davervw | 0:332d4b991d16 | 318 | if (len == 0) |
davervw | 0:332d4b991d16 | 319 | return true; // done! |
davervw | 0:332d4b991d16 | 320 | |
davervw | 0:332d4b991d16 | 321 | // calculate first sector size based on address and length |
davervw | 0:332d4b991d16 | 322 | int32 sector_len = SECTOR_LEN-(addr & (SECTOR_LEN-1)); // remaining space in sector |
davervw | 0:332d4b991d16 | 323 | |
davervw | 0:332d4b991d16 | 324 | while (len > 0) |
davervw | 0:332d4b991d16 | 325 | { |
davervw | 0:332d4b991d16 | 326 | // adjust if buffer than sector size |
davervw | 0:332d4b991d16 | 327 | if (sector_len > len) |
davervw | 0:332d4b991d16 | 328 | sector_len = len; |
davervw | 0:332d4b991d16 | 329 | |
davervw | 0:332d4b991d16 | 330 | // read existing data into entire sector buffer |
davervw | 0:332d4b991d16 | 331 | read(addr & (MAX_ADDR ^ (SECTOR_LEN-1)), sector_buffer, SECTOR_LEN); |
davervw | 0:332d4b991d16 | 332 | |
davervw | 0:332d4b991d16 | 333 | // overwrite with requested data at proper offset |
davervw | 0:332d4b991d16 | 334 | memcpy(sector_buffer + (addr & (SECTOR_LEN-1)), write_buffer, sector_len); |
davervw | 0:332d4b991d16 | 335 | |
davervw | 0:332d4b991d16 | 336 | // reset to beginning of sector |
davervw | 0:332d4b991d16 | 337 | addr = addr ^ (addr & (SECTOR_LEN-1)); |
davervw | 0:332d4b991d16 | 338 | |
davervw | 0:332d4b991d16 | 339 | // erase sector |
davervw | 0:332d4b991d16 | 340 | WREN(); |
davervw | 0:332d4b991d16 | 341 | sector_erase_4k(addr); |
davervw | 0:332d4b991d16 | 342 | |
davervw | 0:332d4b991d16 | 343 | // rewrite the sector |
davervw | 0:332d4b991d16 | 344 | uint8 *p = sector_buffer; |
davervw | 0:332d4b991d16 | 345 | int sectors_in_page = SECTOR_LEN/PAGE_LEN; |
davervw | 0:332d4b991d16 | 346 | for (int i=0; i<sectors_in_page; ++i) |
davervw | 0:332d4b991d16 | 347 | { |
davervw | 0:332d4b991d16 | 348 | page_program(addr, p, PAGE_LEN); |
davervw | 0:332d4b991d16 | 349 | addr += PAGE_LEN; |
davervw | 0:332d4b991d16 | 350 | p += PAGE_LEN; |
davervw | 0:332d4b991d16 | 351 | } |
davervw | 0:332d4b991d16 | 352 | |
davervw | 0:332d4b991d16 | 353 | // adjust where we are, what left to do |
davervw | 0:332d4b991d16 | 354 | write_buffer += sector_len; |
davervw | 0:332d4b991d16 | 355 | len -= sector_len; |
davervw | 0:332d4b991d16 | 356 | sector_len = SECTOR_LEN; |
davervw | 0:332d4b991d16 | 357 | } |
davervw | 0:332d4b991d16 | 358 | |
davervw | 0:332d4b991d16 | 359 | wait_while_busy(); |
davervw | 0:332d4b991d16 | 360 | |
davervw | 0:332d4b991d16 | 361 | return true; |
davervw | 0:332d4b991d16 | 362 | } |
davervw | 0:332d4b991d16 | 363 | |
davervw | 0:332d4b991d16 | 364 | bool SST25VF064C::buffered_write(SST25VF064C::uint8 data) |
davervw | 0:332d4b991d16 | 365 | { |
davervw | 0:332d4b991d16 | 366 | int32& addr = buffered_addr; |
davervw | 0:332d4b991d16 | 367 | |
davervw | 0:332d4b991d16 | 368 | if (addr < 0 || addr > MAX_ADDR) |
davervw | 0:332d4b991d16 | 369 | return false; |
davervw | 0:332d4b991d16 | 370 | |
davervw | 0:332d4b991d16 | 371 | bool result = true; |
davervw | 0:332d4b991d16 | 372 | |
davervw | 0:332d4b991d16 | 373 | // if at sector boundary |
davervw | 0:332d4b991d16 | 374 | if ((addr & (SECTOR_LEN-1)) == 0 || !buffered_erased) |
davervw | 0:332d4b991d16 | 375 | { |
davervw | 0:332d4b991d16 | 376 | WREN(); |
davervw | 0:332d4b991d16 | 377 | sector_erase_4k(addr ^ (addr & (SECTOR_LEN-1))); |
davervw | 0:332d4b991d16 | 378 | buffered_erased = true; |
davervw | 0:332d4b991d16 | 379 | } |
davervw | 0:332d4b991d16 | 380 | |
davervw | 0:332d4b991d16 | 381 | sector_buffer[addr & (SECTOR_LEN-1)] = data; |
davervw | 0:332d4b991d16 | 382 | |
davervw | 0:332d4b991d16 | 383 | ++addr; |
davervw | 0:332d4b991d16 | 384 | |
davervw | 0:332d4b991d16 | 385 | // if at sector boundary |
davervw | 0:332d4b991d16 | 386 | if ((addr & (SECTOR_LEN-1)) == 0) |
davervw | 0:332d4b991d16 | 387 | { |
davervw | 0:332d4b991d16 | 388 | // write sector |
davervw | 0:332d4b991d16 | 389 | result = write(addr-SECTOR_LEN, sector_buffer, SECTOR_LEN); |
davervw | 0:332d4b991d16 | 390 | buffered_erased = false; |
davervw | 0:332d4b991d16 | 391 | |
davervw | 0:332d4b991d16 | 392 | // read more |
davervw | 0:332d4b991d16 | 393 | if (addr != MAX_ADDR) |
davervw | 0:332d4b991d16 | 394 | result = result && read(addr, sector_buffer, SECTOR_LEN); |
davervw | 0:332d4b991d16 | 395 | } |
davervw | 0:332d4b991d16 | 396 | |
davervw | 0:332d4b991d16 | 397 | return result; |
davervw | 0:332d4b991d16 | 398 | } |
davervw | 0:332d4b991d16 | 399 | |
davervw | 0:332d4b991d16 | 400 | bool SST25VF064C::buffered_write(SST25VF064C::uint8* src, int len) |
davervw | 0:332d4b991d16 | 401 | { |
davervw | 0:332d4b991d16 | 402 | bool result = true; |
davervw | 0:332d4b991d16 | 403 | |
davervw | 0:332d4b991d16 | 404 | while (result && len > 0) |
davervw | 0:332d4b991d16 | 405 | { |
davervw | 0:332d4b991d16 | 406 | result = buffered_write(*src); |
davervw | 0:332d4b991d16 | 407 | --len; |
davervw | 0:332d4b991d16 | 408 | ++src; |
davervw | 0:332d4b991d16 | 409 | } |
davervw | 0:332d4b991d16 | 410 | |
davervw | 0:332d4b991d16 | 411 | return result; |
davervw | 0:332d4b991d16 | 412 | } |
davervw | 0:332d4b991d16 | 413 | |
davervw | 0:332d4b991d16 | 414 | SST25VF064C::uint8 SST25VF064C::buffered_read() |
davervw | 0:332d4b991d16 | 415 | { |
davervw | 0:332d4b991d16 | 416 | int32& addr = buffered_addr; |
davervw | 0:332d4b991d16 | 417 | if (addr < 0 || addr >= MAX_ADDR) |
davervw | 0:332d4b991d16 | 418 | { |
davervw | 0:332d4b991d16 | 419 | addr = -1; |
davervw | 0:332d4b991d16 | 420 | return 0xff; |
davervw | 0:332d4b991d16 | 421 | } |
davervw | 0:332d4b991d16 | 422 | uint8 data = sector_buffer[addr & (SECTOR_LEN-1)]; |
davervw | 0:332d4b991d16 | 423 | ++addr; |
davervw | 0:332d4b991d16 | 424 | if ((addr & (SECTOR_LEN-1)) == 0) |
davervw | 0:332d4b991d16 | 425 | { |
davervw | 0:332d4b991d16 | 426 | if (buffered_erased) |
davervw | 0:332d4b991d16 | 427 | { |
davervw | 0:332d4b991d16 | 428 | write(addr-SECTOR_LEN, sector_buffer, SECTOR_LEN); |
davervw | 0:332d4b991d16 | 429 | buffered_erased = false; |
davervw | 0:332d4b991d16 | 430 | } |
davervw | 0:332d4b991d16 | 431 | if (addr == MAX_ADDR) |
davervw | 0:332d4b991d16 | 432 | addr = -1; |
davervw | 0:332d4b991d16 | 433 | else |
davervw | 0:332d4b991d16 | 434 | read(addr, sector_buffer, SECTOR_LEN); |
davervw | 0:332d4b991d16 | 435 | } |
davervw | 0:332d4b991d16 | 436 | return data; |
davervw | 0:332d4b991d16 | 437 | } |
davervw | 0:332d4b991d16 | 438 | |
davervw | 0:332d4b991d16 | 439 | bool SST25VF064C::buffered_read(SST25VF064C::uint8* dest, int len) |
davervw | 0:332d4b991d16 | 440 | { |
davervw | 0:332d4b991d16 | 441 | while (len > 0) |
davervw | 0:332d4b991d16 | 442 | { |
davervw | 0:332d4b991d16 | 443 | if (buffered_addr < 0 || buffered_addr >= MAX_ADDR) |
davervw | 0:332d4b991d16 | 444 | return false; |
davervw | 0:332d4b991d16 | 445 | |
davervw | 0:332d4b991d16 | 446 | *dest = buffered_read(); |
davervw | 0:332d4b991d16 | 447 | --len; |
davervw | 0:332d4b991d16 | 448 | ++dest; |
davervw | 0:332d4b991d16 | 449 | } |
davervw | 0:332d4b991d16 | 450 | |
davervw | 0:332d4b991d16 | 451 | return true; |
davervw | 0:332d4b991d16 | 452 | } |
davervw | 0:332d4b991d16 | 453 | |
davervw | 0:332d4b991d16 | 454 | void SST25VF064C::buffered_seek(SST25VF064C::int32 addr) |
davervw | 0:332d4b991d16 | 455 | { |
davervw | 0:332d4b991d16 | 456 | if (buffered_erased) |
davervw | 0:332d4b991d16 | 457 | write(buffered_addr ^ (buffered_addr & (SECTOR_LEN-1)), sector_buffer, SECTOR_LEN); |
davervw | 0:332d4b991d16 | 458 | if (addr < 0 || addr >= MAX_ADDR) |
davervw | 0:332d4b991d16 | 459 | { |
davervw | 0:332d4b991d16 | 460 | buffered_addr = -1; |
davervw | 0:332d4b991d16 | 461 | buffered_erased = false; |
davervw | 0:332d4b991d16 | 462 | } |
davervw | 0:332d4b991d16 | 463 | else |
davervw | 0:332d4b991d16 | 464 | { |
davervw | 0:332d4b991d16 | 465 | read(addr ^ (addr & (SECTOR_LEN-1)), sector_buffer, SECTOR_LEN); |
davervw | 0:332d4b991d16 | 466 | buffered_addr = addr; |
davervw | 0:332d4b991d16 | 467 | buffered_erased = false; |
davervw | 0:332d4b991d16 | 468 | } |
davervw | 0:332d4b991d16 | 469 | } |
davervw | 0:332d4b991d16 | 470 | |
davervw | 0:332d4b991d16 | 471 | void SST25VF064C::buffered_sync() |
davervw | 0:332d4b991d16 | 472 | { |
davervw | 0:332d4b991d16 | 473 | int32& addr = buffered_addr; |
davervw | 0:332d4b991d16 | 474 | |
davervw | 0:332d4b991d16 | 475 | if (buffered_erased) |
davervw | 0:332d4b991d16 | 476 | { |
davervw | 0:332d4b991d16 | 477 | write(addr ^ (addr & (SECTOR_LEN-1)), sector_buffer, SECTOR_LEN); |
davervw | 0:332d4b991d16 | 478 | buffered_erased = false; |
davervw | 0:332d4b991d16 | 479 | } |
davervw | 0:332d4b991d16 | 480 | } |