lib : https://developer.mbed.org/users/DimiterK/code/W25Q64FVSSIG/ I try a little change code.
Fork of W25Q64FVSSIG by
W25Q64FV.cpp@1:259668edf734, 2017-09-08 (annotated)
- Committer:
- i_am_kitsune
- Date:
- Fri Sep 08 05:51:40 2017 +0000
- Revision:
- 1:259668edf734
- Parent:
- 0:b71060e03299
Hexiwear flash memory ; W25Q64FV; 20170908;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
DimiterK | 0:b71060e03299 | 1 | #include "W25Q64FV.h" |
DimiterK | 0:b71060e03299 | 2 | |
DimiterK | 0:b71060e03299 | 3 | W25Q64FV::W25Q64FV(PinName mosi, PinName miso, PinName sclk, PinName cs, int frequency) |
DimiterK | 0:b71060e03299 | 4 | { |
DimiterK | 0:b71060e03299 | 5 | |
DimiterK | 0:b71060e03299 | 6 | this->cs = new DigitalOut(cs); |
DimiterK | 0:b71060e03299 | 7 | this->cs->write(true); |
DimiterK | 0:b71060e03299 | 8 | this->frequency = frequency; |
DimiterK | 0:b71060e03299 | 9 | |
DimiterK | 0:b71060e03299 | 10 | spi = new SPI(mosi, miso, sclk); |
DimiterK | 0:b71060e03299 | 11 | spi->format(8, 0); |
DimiterK | 0:b71060e03299 | 12 | spi->frequency(frequency); |
DimiterK | 0:b71060e03299 | 13 | } |
DimiterK | 0:b71060e03299 | 14 | |
DimiterK | 0:b71060e03299 | 15 | W25Q64FV::~W25Q64FV() |
DimiterK | 0:b71060e03299 | 16 | { |
DimiterK | 0:b71060e03299 | 17 | delete spi; |
DimiterK | 0:b71060e03299 | 18 | delete cs; |
DimiterK | 0:b71060e03299 | 19 | } |
DimiterK | 0:b71060e03299 | 20 | |
DimiterK | 0:b71060e03299 | 21 | uint16_t W25Q64FV::Id() |
DimiterK | 0:b71060e03299 | 22 | { |
DimiterK | 0:b71060e03299 | 23 | cs->write(0); |
DimiterK | 0:b71060e03299 | 24 | spi->write(CMD_MANU_ID); |
DimiterK | 0:b71060e03299 | 25 | spi->write(0); |
DimiterK | 0:b71060e03299 | 26 | spi->write(0); |
DimiterK | 0:b71060e03299 | 27 | spi->write(0); |
DimiterK | 0:b71060e03299 | 28 | unsigned id = (spi->write(0) << 8) | spi->write(0); |
DimiterK | 0:b71060e03299 | 29 | cs->write(1); |
DimiterK | 0:b71060e03299 | 30 | return id; |
DimiterK | 0:b71060e03299 | 31 | } |
DimiterK | 0:b71060e03299 | 32 | |
i_am_kitsune | 1:259668edf734 | 33 | void W25Q64FV::W25Q64_readManufacturer(uint8_t* d) { |
i_am_kitsune | 1:259668edf734 | 34 | |
i_am_kitsune | 1:259668edf734 | 35 | cs -> write(0); |
i_am_kitsune | 1:259668edf734 | 36 | spi->write(CMD_MANU_ID); |
i_am_kitsune | 1:259668edf734 | 37 | for (uint8_t i =0; i <5; i++) { |
i_am_kitsune | 1:259668edf734 | 38 | d[i] = spi->write(0); |
i_am_kitsune | 1:259668edf734 | 39 | } |
i_am_kitsune | 1:259668edf734 | 40 | cs -> write(1); |
i_am_kitsune | 1:259668edf734 | 41 | } |
i_am_kitsune | 1:259668edf734 | 42 | |
DimiterK | 0:b71060e03299 | 43 | uint32_t W25Q64FV::JEDECId() |
DimiterK | 0:b71060e03299 | 44 | { |
DimiterK | 0:b71060e03299 | 45 | cs->write(0); |
DimiterK | 0:b71060e03299 | 46 | spi->write(CMD_JEDEC_ID); |
DimiterK | 0:b71060e03299 | 47 | unsigned id = (spi->write(0) << 16) | (spi->write(0) << 8) | spi->write(0); |
DimiterK | 0:b71060e03299 | 48 | cs->write(1); |
DimiterK | 0:b71060e03299 | 49 | return id; |
DimiterK | 0:b71060e03299 | 50 | } |
DimiterK | 0:b71060e03299 | 51 | |
DimiterK | 0:b71060e03299 | 52 | void W25Q64FV::writeEnable(void) |
DimiterK | 0:b71060e03299 | 53 | { |
DimiterK | 0:b71060e03299 | 54 | cs->write(0); |
DimiterK | 0:b71060e03299 | 55 | spi->write(CMD_WREN); |
DimiterK | 0:b71060e03299 | 56 | cs->write(1); |
DimiterK | 0:b71060e03299 | 57 | } |
DimiterK | 0:b71060e03299 | 58 | |
DimiterK | 0:b71060e03299 | 59 | void W25Q64FV::writeDisable(void) |
DimiterK | 0:b71060e03299 | 60 | { |
DimiterK | 0:b71060e03299 | 61 | cs->write(0); |
DimiterK | 0:b71060e03299 | 62 | spi->write(CMD_WR_DISABLE) ; |
DimiterK | 0:b71060e03299 | 63 | cs->write(1); |
DimiterK | 0:b71060e03299 | 64 | } |
DimiterK | 0:b71060e03299 | 65 | |
DimiterK | 0:b71060e03299 | 66 | uint8_t W25Q64FV::readStatus(void) |
DimiterK | 0:b71060e03299 | 67 | { |
DimiterK | 0:b71060e03299 | 68 | uint8_t data ; |
DimiterK | 0:b71060e03299 | 69 | cs->write(0); |
DimiterK | 0:b71060e03299 | 70 | spi->write(CMD_RDSR1) ; |
DimiterK | 0:b71060e03299 | 71 | data = spi->write(DUMMY) ; // dummy |
DimiterK | 0:b71060e03299 | 72 | cs->write(1); |
DimiterK | 0:b71060e03299 | 73 | return( data ) ; |
DimiterK | 0:b71060e03299 | 74 | } |
DimiterK | 0:b71060e03299 | 75 | |
DimiterK | 0:b71060e03299 | 76 | void W25Q64FV::writeStatusReg(int addr) // Write SR cmd 01h + 3B data |
DimiterK | 0:b71060e03299 | 77 | { |
DimiterK | 0:b71060e03299 | 78 | cs->write(0); |
DimiterK | 0:b71060e03299 | 79 | spi->write(CMD_WRSR1) ; // Write SR cmd 01h |
DimiterK | 0:b71060e03299 | 80 | spi->write((addr >> 16)&0xFF) ; // address |
DimiterK | 0:b71060e03299 | 81 | spi->write((addr >> 8)&0xFF) ; |
DimiterK | 0:b71060e03299 | 82 | spi->write(addr & 0xFF) ; |
DimiterK | 0:b71060e03299 | 83 | cs->write(1); |
DimiterK | 0:b71060e03299 | 84 | } |
DimiterK | 0:b71060e03299 | 85 | |
DimiterK | 0:b71060e03299 | 86 | void W25Q64FV::writeSecurityReg(int addr) // WRSCUR cmd 2Fh + 1B data |
DimiterK | 0:b71060e03299 | 87 | { |
DimiterK | 0:b71060e03299 | 88 | cs->write(0); |
DimiterK | 0:b71060e03299 | 89 | // spi->write(CMD_WRSCUR) ; // Write SR cmd 01h |
DimiterK | 0:b71060e03299 | 90 | spi->write(addr & 0xFF) ; |
DimiterK | 0:b71060e03299 | 91 | cs->write(1); |
DimiterK | 0:b71060e03299 | 92 | } |
DimiterK | 0:b71060e03299 | 93 | |
DimiterK | 0:b71060e03299 | 94 | |
DimiterK | 0:b71060e03299 | 95 | uint8_t W25Q64FV::readByte(int addr) // Single Byte Read |
DimiterK | 0:b71060e03299 | 96 | { |
DimiterK | 0:b71060e03299 | 97 | uint8_t data ; |
DimiterK | 0:b71060e03299 | 98 | cs->write(0); |
DimiterK | 0:b71060e03299 | 99 | spi->write(CMD_READ_DATA) ; // send 03h |
DimiterK | 0:b71060e03299 | 100 | spi->write((addr >> 16)&0xFF) ; |
DimiterK | 0:b71060e03299 | 101 | spi->write((addr >> 8)&0xFF) ; |
DimiterK | 0:b71060e03299 | 102 | spi->write(addr & 0xFF) ; |
DimiterK | 0:b71060e03299 | 103 | data = spi->write(DUMMY) ; // write data is dummy |
DimiterK | 0:b71060e03299 | 104 | cs->write(1); |
DimiterK | 0:b71060e03299 | 105 | return( data ) ; // return 1 byte |
DimiterK | 0:b71060e03299 | 106 | } |
DimiterK | 0:b71060e03299 | 107 | |
DimiterK | 0:b71060e03299 | 108 | bool W25Q64FV::read(uint32_t addr, uint8_t* dst, uint32_t len) |
DimiterK | 0:b71060e03299 | 109 | { |
DimiterK | 0:b71060e03299 | 110 | cs->write(0); |
DimiterK | 0:b71060e03299 | 111 | spi->write(0x03); |
DimiterK | 0:b71060e03299 | 112 | spi->write((addr >> 16) & 0xff); |
DimiterK | 0:b71060e03299 | 113 | spi->write((addr >> 8) & 0xff); |
DimiterK | 0:b71060e03299 | 114 | spi->write(addr & 0xff); |
DimiterK | 0:b71060e03299 | 115 | for (uint32_t i=0; i<len; ++i) |
DimiterK | 0:b71060e03299 | 116 | dst[i] = spi->write(0); |
DimiterK | 0:b71060e03299 | 117 | cs->write(1); |
DimiterK | 0:b71060e03299 | 118 | |
DimiterK | 0:b71060e03299 | 119 | return true; |
DimiterK | 0:b71060e03299 | 120 | } |
DimiterK | 0:b71060e03299 | 121 | |
DimiterK | 0:b71060e03299 | 122 | void W25Q64FV::hsread(uint32_t addr, uint8_t* dst, uint32_t len, int frequency) |
DimiterK | 0:b71060e03299 | 123 | { |
DimiterK | 0:b71060e03299 | 124 | int save_frequency = this->frequency; |
DimiterK | 0:b71060e03299 | 125 | spi->frequency(frequency); |
DimiterK | 0:b71060e03299 | 126 | cs->write(0); |
DimiterK | 0:b71060e03299 | 127 | spi->write(0x0B); |
DimiterK | 0:b71060e03299 | 128 | spi->write((addr >> 16) & 0xff); |
DimiterK | 0:b71060e03299 | 129 | spi->write((addr >> 8) & 0xff); |
DimiterK | 0:b71060e03299 | 130 | spi->write(addr & 0xff); |
DimiterK | 0:b71060e03299 | 131 | spi->write(0); // dummy |
DimiterK | 0:b71060e03299 | 132 | for (uint32_t i=0; i<len; ++i) |
DimiterK | 0:b71060e03299 | 133 | dst[i] = spi->write(0); |
DimiterK | 0:b71060e03299 | 134 | cs->write(1); |
DimiterK | 0:b71060e03299 | 135 | spi->frequency(save_frequency); |
DimiterK | 0:b71060e03299 | 136 | } |
DimiterK | 0:b71060e03299 | 137 | |
DimiterK | 0:b71060e03299 | 138 | uint8_t W25Q64FV::readSFDP(int addr) // Read SFDP |
DimiterK | 0:b71060e03299 | 139 | { |
DimiterK | 0:b71060e03299 | 140 | uint8_t data ; |
DimiterK | 0:b71060e03299 | 141 | cs->write(0); |
DimiterK | 0:b71060e03299 | 142 | spi->write(CMD_READ_SFDP) ; // send cmd 5Ah |
DimiterK | 0:b71060e03299 | 143 | spi->write((addr >> 16)&0xFF) ; // address[23:16] |
DimiterK | 0:b71060e03299 | 144 | spi->write((addr >> 8)&0xFF) ; // address[15:8] |
DimiterK | 0:b71060e03299 | 145 | spi->write(addr & 0xFF) ; // address[7:0] |
DimiterK | 0:b71060e03299 | 146 | spi->write(DUMMY) ; // dummy cycle |
DimiterK | 0:b71060e03299 | 147 | data = spi->write(DUMMY) ; // return 1 byte |
DimiterK | 0:b71060e03299 | 148 | cs->write(1); |
DimiterK | 0:b71060e03299 | 149 | return( data ) ; |
DimiterK | 0:b71060e03299 | 150 | } |
DimiterK | 0:b71060e03299 | 151 | |
DimiterK | 0:b71060e03299 | 152 | uint8_t W25Q64FV::wait_while_busy(void) |
DimiterK | 0:b71060e03299 | 153 | { |
DimiterK | 0:b71060e03299 | 154 | uint8_t temp = 0; |
DimiterK | 0:b71060e03299 | 155 | cs->write(0); //Enable device |
DimiterK | 0:b71060e03299 | 156 | spi->write(CMD_RDSR1); //Send RDSR command |
DimiterK | 0:b71060e03299 | 157 | temp = spi->write(DUMMY); |
DimiterK | 0:b71060e03299 | 158 | cs->write(1); //Disable |
DimiterK | 0:b71060e03299 | 159 | if (temp & 0x01) return 1; |
DimiterK | 0:b71060e03299 | 160 | else return 0; |
DimiterK | 0:b71060e03299 | 161 | } |
DimiterK | 0:b71060e03299 | 162 | |
DimiterK | 0:b71060e03299 | 163 | |
DimiterK | 0:b71060e03299 | 164 | bool W25Q64FV::page_program(uint32_t addr, uint8_t* write_buffer, uint8_t len) |
DimiterK | 0:b71060e03299 | 165 | { |
DimiterK | 0:b71060e03299 | 166 | // no point in writing FF as an empty sector already has those |
DimiterK | 0:b71060e03299 | 167 | // (and if not empty, write won't succeed) |
DimiterK | 0:b71060e03299 | 168 | bool skipped = false; |
DimiterK | 0:b71060e03299 | 169 | while (len > 0 && *write_buffer == 0xFF) |
DimiterK | 0:b71060e03299 | 170 | { |
DimiterK | 0:b71060e03299 | 171 | ++write_buffer; |
DimiterK | 0:b71060e03299 | 172 | --len; |
DimiterK | 0:b71060e03299 | 173 | ++addr; |
DimiterK | 0:b71060e03299 | 174 | skipped = true; |
DimiterK | 0:b71060e03299 | 175 | } |
DimiterK | 0:b71060e03299 | 176 | if (len == 0 && skipped) |
DimiterK | 0:b71060e03299 | 177 | return true; // special case when succeeds when nothing to do |
DimiterK | 0:b71060e03299 | 178 | |
DimiterK | 0:b71060e03299 | 179 | if (len < 1 || len > 256) |
DimiterK | 0:b71060e03299 | 180 | return false; |
DimiterK | 0:b71060e03299 | 181 | |
DimiterK | 0:b71060e03299 | 182 | // write enable |
DimiterK | 0:b71060e03299 | 183 | writeEnable(); |
DimiterK | 0:b71060e03299 | 184 | |
DimiterK | 0:b71060e03299 | 185 | cs->write(0); |
DimiterK | 0:b71060e03299 | 186 | spi->write(0x02); |
DimiterK | 0:b71060e03299 | 187 | spi->write((uint8_t)(addr >> 16)); |
DimiterK | 0:b71060e03299 | 188 | spi->write((uint8_t)(addr >> 8)); |
DimiterK | 0:b71060e03299 | 189 | spi->write((uint8_t)addr); |
DimiterK | 0:b71060e03299 | 190 | for (uint16_t i=0; i<len; ++i) |
DimiterK | 0:b71060e03299 | 191 | spi->write(write_buffer[i]); |
DimiterK | 0:b71060e03299 | 192 | cs->write(1); |
DimiterK | 0:b71060e03299 | 193 | wait_while_busy(); |
DimiterK | 0:b71060e03299 | 194 | |
DimiterK | 0:b71060e03299 | 195 | return true; |
DimiterK | 0:b71060e03299 | 196 | } |
DimiterK | 0:b71060e03299 | 197 | |
DimiterK | 0:b71060e03299 | 198 | void W25Q64FV::sector_erase_4k(uint32_t addr) |
DimiterK | 0:b71060e03299 | 199 | { |
DimiterK | 0:b71060e03299 | 200 | cs->write(0); |
DimiterK | 0:b71060e03299 | 201 | spi->write(CMD_ERASE_SECTOR); |
DimiterK | 0:b71060e03299 | 202 | spi->write((uint8_t)(addr >> 16)); |
DimiterK | 0:b71060e03299 | 203 | spi->write((uint8_t)(addr >> 8)); |
DimiterK | 0:b71060e03299 | 204 | spi->write((uint8_t)addr); |
DimiterK | 0:b71060e03299 | 205 | cs->write(1); |
DimiterK | 0:b71060e03299 | 206 | wait_while_busy(); |
DimiterK | 0:b71060e03299 | 207 | } |
DimiterK | 0:b71060e03299 | 208 | |
DimiterK | 0:b71060e03299 | 209 | void W25Q64FV::block_erase_32k(uint32_t addr) |
DimiterK | 0:b71060e03299 | 210 | { |
DimiterK | 0:b71060e03299 | 211 | cs->write(0); |
DimiterK | 0:b71060e03299 | 212 | spi->write(CMD_ERASE_BLOCK32); |
DimiterK | 0:b71060e03299 | 213 | spi->write((uint8_t)(addr >> 16)); |
DimiterK | 0:b71060e03299 | 214 | spi->write((uint8_t)(addr >> 8)); |
DimiterK | 0:b71060e03299 | 215 | spi->write((uint8_t)addr); |
DimiterK | 0:b71060e03299 | 216 | cs->write(1); |
DimiterK | 0:b71060e03299 | 217 | wait_while_busy(); |
DimiterK | 0:b71060e03299 | 218 | } |
DimiterK | 0:b71060e03299 | 219 | |
DimiterK | 0:b71060e03299 | 220 | void W25Q64FV::block_erase_64k(uint32_t addr) |
DimiterK | 0:b71060e03299 | 221 | { |
DimiterK | 0:b71060e03299 | 222 | cs->write(0); |
DimiterK | 0:b71060e03299 | 223 | spi->write(CMD_ERASE_BLOCK64); |
DimiterK | 0:b71060e03299 | 224 | spi->write((uint8_t)(addr >> 16)); |
DimiterK | 0:b71060e03299 | 225 | spi->write((uint8_t)(addr >> 8)); |
DimiterK | 0:b71060e03299 | 226 | spi->write((uint8_t)addr); |
DimiterK | 0:b71060e03299 | 227 | cs->write(1); |
DimiterK | 0:b71060e03299 | 228 | wait_while_busy(); |
DimiterK | 0:b71060e03299 | 229 | } |
DimiterK | 0:b71060e03299 | 230 | |
DimiterK | 0:b71060e03299 | 231 | void W25Q64FV::chip_erase() |
DimiterK | 0:b71060e03299 | 232 | { |
DimiterK | 0:b71060e03299 | 233 | cs->write(0); |
DimiterK | 0:b71060e03299 | 234 | spi->write(CMD_ERASE_CHIP); |
DimiterK | 0:b71060e03299 | 235 | cs->write(1); |
DimiterK | 0:b71060e03299 | 236 | wait_while_busy(); |
DimiterK | 0:b71060e03299 | 237 | } |
DimiterK | 0:b71060e03299 | 238 | |
DimiterK | 0:b71060e03299 | 239 | |
DimiterK | 0:b71060e03299 | 240 | |
DimiterK | 0:b71060e03299 | 241 | |
DimiterK | 0:b71060e03299 | 242 | |
DimiterK | 0:b71060e03299 | 243 | |
DimiterK | 0:b71060e03299 | 244 | void W25Q64FV::writeArray(uint32_t address, uint8_t* pData, uint32_t arrayLength) |
DimiterK | 0:b71060e03299 | 245 | { |
DimiterK | 0:b71060e03299 | 246 | unsigned int i = 0; |
DimiterK | 0:b71060e03299 | 247 | cs->write(0); //Enable device |
DimiterK | 0:b71060e03299 | 248 | spi->write(CMD_WREN); //Send WREN command |
DimiterK | 0:b71060e03299 | 249 | cs->write(1); //Disable device |
DimiterK | 0:b71060e03299 | 250 | |
DimiterK | 0:b71060e03299 | 251 | cs->write(0); //Enable device |
DimiterK | 0:b71060e03299 | 252 | spi->write(CMD_PAGEPROG); //Send Byte Program command |
DimiterK | 0:b71060e03299 | 253 | spi->write((uint8_t)(address >> 16) & 0xFF); |
DimiterK | 0:b71060e03299 | 254 | spi->write((uint8_t)(address >> 8) & 0xFF); |
DimiterK | 0:b71060e03299 | 255 | spi->write(0x00); |
DimiterK | 0:b71060e03299 | 256 | |
DimiterK | 0:b71060e03299 | 257 | for (i=0;i<arrayLength;i++) |
DimiterK | 0:b71060e03299 | 258 | { |
DimiterK | 0:b71060e03299 | 259 | spi->write(pData[i]); //Send byte to be programmed |
DimiterK | 0:b71060e03299 | 260 | } |
DimiterK | 0:b71060e03299 | 261 | cs->write(1); //Disable device |
DimiterK | 0:b71060e03299 | 262 | |
DimiterK | 0:b71060e03299 | 263 | //Wait Busy |
DimiterK | 0:b71060e03299 | 264 | while ((readStatus() & 0x01) == 0x01) //Waste time until not busy |
DimiterK | 0:b71060e03299 | 265 | { |
DimiterK | 0:b71060e03299 | 266 | } |
DimiterK | 0:b71060e03299 | 267 | } |
DimiterK | 0:b71060e03299 | 268 | |
DimiterK | 0:b71060e03299 | 269 | |
DimiterK | 0:b71060e03299 | 270 | void W25Q64FV::readArray(uint32_t address, uint8_t* pData, uint32_t arrayLength) |
DimiterK | 0:b71060e03299 | 271 | { |
DimiterK | 0:b71060e03299 | 272 | unsigned int i = 0; |
DimiterK | 0:b71060e03299 | 273 | |
DimiterK | 0:b71060e03299 | 274 | cs->write(0); //Enable device |
DimiterK | 0:b71060e03299 | 275 | spi->write(CMD_READ_DATA); //Read command |
DimiterK | 0:b71060e03299 | 276 | spi->write((uint8_t)(address >> 16)); |
DimiterK | 0:b71060e03299 | 277 | spi->write((uint8_t)(address >> 8)); |
DimiterK | 0:b71060e03299 | 278 | spi->write((uint8_t) address); |
DimiterK | 0:b71060e03299 | 279 | |
DimiterK | 0:b71060e03299 | 280 | for (i = 0; i <arrayLength; i++) //Read until no_bytes is reached |
DimiterK | 0:b71060e03299 | 281 | { |
DimiterK | 0:b71060e03299 | 282 | pData[i] = spi->write(DUMMY); //Receive bytes |
DimiterK | 0:b71060e03299 | 283 | } |
DimiterK | 0:b71060e03299 | 284 | cs->write(1); //Disable device |
DimiterK | 0:b71060e03299 | 285 | |
DimiterK | 0:b71060e03299 | 286 | //Wait Busy |
DimiterK | 0:b71060e03299 | 287 | while (readStatus() & 0x01) //Waste time until not busy |
DimiterK | 0:b71060e03299 | 288 | { |
DimiterK | 0:b71060e03299 | 289 | } |
DimiterK | 0:b71060e03299 | 290 | } |
DimiterK | 0:b71060e03299 | 291 | |
DimiterK | 0:b71060e03299 | 292 | |
DimiterK | 0:b71060e03299 | 293 |